From 273e4706ba0fb43e63ed8461263635fd78704210 Mon Sep 17 00:00:00 2001 From: Branislav Kojic Date: Wed, 13 Nov 2024 14:02:03 +0100 Subject: [PATCH] Availability tests (#429) * Add Availability Tests * Availability Tests changes; LT result artifact * Notification status * Small text changes * Potencial Slack problem with link * Get Public Address from Private Key --- .github/workflows/availability-tests.yml | 189 ++++++++++++++++++ .github/workflows/deploy-network.yml | 3 + .github/workflows/load-test.yml | 14 +- .github/workflows/nightly.yml | 31 ++- .../notification-availability-test.yml | 108 ++++++++++ .github/workflows/notification-load-test.yml | 13 ++ .github/workflows/notification-nightly.yml | 8 + 7 files changed, 359 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/availability-tests.yml create mode 100644 .github/workflows/notification-availability-test.yml diff --git a/.github/workflows/availability-tests.yml b/.github/workflows/availability-tests.yml new file mode 100644 index 0000000000..b263c3006f --- /dev/null +++ b/.github/workflows/availability-tests.yml @@ -0,0 +1,189 @@ +--- +name: Availability Tests +on: + workflow_dispatch: + inputs: + environment: + description: The environment to run against + required: true + type: string + rpc_url: + description: JSON-RPC URL + required: true + type: string + fund_amount: + description: Amount in Ether to fund + required: true + type: string + default: "5" + london: + description: Is London fork active? + required: true + type: boolean + default: true + notification: + description: Notification + type: boolean + default: true + workflow_call: + inputs: + environment: + description: The environment to run against + required: true + type: string + rpc_url: + description: JSON-RPC URL + required: true + type: string + fund_amount: + description: Amount in Ether to fund + required: true + type: string + london: + description: Is London fork active? + required: true + type: boolean + notification: + description: Notification + type: boolean + required: true + outputs: + availability_test_status: + value: ${{ jobs.availability_test.outputs.availability_test_status }} + produce_blocks: + value: ${{ jobs.availability_test.outputs.produce_blocks }} + fund_status: + value: ${{ jobs.availability_test.outputs.fund_status }} + check_deployed_smart_contract_status: + value: ${{ jobs.availability_test.outputs.check_deployed_smart_contract_status }} + method_set_status: + value: ${{ jobs.availability_test.outputs.method_set_status }} + method_get_status: + value: ${{ jobs.availability_test.outputs.method_get_status }} + secrets: + FAUCET_PRIVATE_KEY: + required: true + ACCOUNT_PRIVATE_KEY: + required: true + SLACK_WEBHOOK_URL: + required: true + +jobs: + availability_test: + name: Availability Test + runs-on: ubuntu-latest + outputs: + availability_test_status: ${{ steps.final_status.outputs.status }} + produce_blocks: ${{ steps.latest_block_number.outputs.produce_blocks }} + fund_status: ${{ steps.fund.outputs.status }} + check_deployed_smart_contract_status: ${{ steps.check_deployed_smart_contract.outputs.status }} + method_set_status: ${{ steps.method_set.outputs.status }} + method_get_status: ${{ steps.method_get.outputs.status }} + steps: + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly-f625d0fa7c51e65b4bf1e8f7931cd1c6e2e285e9 + - name: Get latest block number + id: latest_block_number + run: | + current_block_number=$(cast to-dec `cast rpc --rpc-url ${{ inputs.rpc_url }} eth_blockNumber | sed 's/"//g'`) + sleep 15 + latest_block_number=$(cast to-dec `cast rpc --rpc-url ${{ inputs.rpc_url }} eth_blockNumber | sed 's/"//g'`) + if [ $current_block_number != $latest_block_number ]; then + echo "produce_blocks=true" >> $GITHUB_OUTPUT + fi + - name: Fund account + id: fund + run: | + public_address=$(cast wallet address --private-key ${{ secrets.ACCOUNT_PRIVATE_KEY }}) + current_balance=$(cast rpc --rpc-url ${{ inputs.rpc_url }} eth_getBalance $public_address latest | sed 's/"//g') + current_balance_converted=$(echo "`cast to-dec $current_balance`/1000000000000000000" | bc -l) + fund=$(cast send --rpc-url ${{ inputs.rpc_url }} --private-key ${{ secrets.FAUCET_PRIVATE_KEY }} --value ${{ inputs.fund_amount }}ether $public_address `[[ ${{ inputs.london }} == false ]] && echo --legacy`) + if [ $(echo "$fund" | grep -c "transactionHash") -eq 1 ]; then + new_balance=$(cast rpc --rpc-url ${{ inputs.rpc_url }} eth_getBalance $public_address latest | sed 's/"//g') + new_balance_converted=$(echo "`cast to-dec $new_balance`/1000000000000000000" | bc -l) + if [ $current_balance_converted != $new_balance_converted ]; then + echo "status=true" >> $GITHUB_OUTPUT + fi + fi + - name: Forge Init + run: forge init . --no-git + - name: Create Simple Smart Contract + run: | + cat < src/SimpleContract.sol + // SPDX-License-Identifier: MIT + + pragma solidity ^0.8.2; + + contract SimpleContract { + uint256 number; + + function set(uint256 num) public { + number = num; + } + + function get() public view returns (uint256) { + return number; + } + } + EOF + - name: Forge Compile + run: forge compile + - name: Deploy Smart Contract to the network + id: deploy_smart_contract + if: steps.fund.outputs.status + run: | + output=$(forge create SimpleContract --rpc-url ${{ inputs.rpc_url }} --private-key ${{ secrets.ACCOUNT_PRIVATE_KEY }} `[[ ${{ inputs.london }} == false ]] && echo --legacy`) + address=$(echo "$output" | awk -F "Deployed to: | Transaction hash:" '{print $2}') + echo "hash=$(jq -Rn --arg value $address '$value')" >> $GITHUB_OUTPUT + - name: Check if Smart Contract deployed successfully + id: check_deployed_smart_contract + if: steps.fund.outputs.status + run: | + bytecode=$(cast rpc --rpc-url ${{ inputs.rpc_url }} eth_getCode ${{ steps.deploy_smart_contract.outputs.hash }} latest | sed 's/"//g') + if [ $bytecode != "0x" ] && [ $bytecode != "" ]; then + echo "status=true" >> $GITHUB_OUTPUT + fi + - name: Call set() method from Smart Contract + id: method_set + if: steps.check_deployed_smart_contract.outputs.status + run: | + output=$(cast send --rpc-url ${{ inputs.rpc_url }} --private-key ${{ secrets.ACCOUNT_PRIVATE_KEY }} ${{ steps.deploy_smart_contract.outputs.hash }} "function set(uint256)" 100 `[[ ${{ inputs.london }} == false ]] && echo --legacy`) + if [ $(echo "$output" | grep -c "transactionHash") -eq 1 ]; then + echo "status=true" >> $GITHUB_OUTPUT + fi + - name: Call get() method from Smart Contract + id: method_get + if: steps.check_deployed_smart_contract.outputs.status && steps.method_set.outputs.status + run: | + output=$(cast call --rpc-url ${{ inputs.rpc_url }} ${{ steps.deploy_smart_contract.outputs.hash }} "function get()" `[[ ${{ inputs.london }} == false ]] && echo --legacy`) + if [ $(cast to-dec `echo $output`) -eq 100 ]; then + echo "status=true" >> $GITHUB_OUTPUT + fi + - name: Final status + id: final_status + run: | + if [ ${{ steps.latest_block_number.outputs.produce_blocks }} = "true" ] && + [ ${{ steps.fund.outputs.status }} = "true" ] && + [ ${{ steps.check_deployed_smart_contract.outputs.status }} = "true" ] && + [ ${{ steps.method_set.outputs.status }} = "true" ] && + [ ${{ steps.method_get.outputs.status }} = "true" ]; then + echo "status=true" >> $GITHUB_OUTPUT + fi + + notification: + name: Availability Test Notification + needs: availability_test + uses: ./.github/workflows/notification-availability-test.yml + if: ((success() || failure()) && inputs.notification) + with: + environment: ${{ inputs.environment }} + availability_test_status: ${{ needs.availability_test.outputs.availability_test_status }} + produce_blocks: ${{ needs.availability_test.outputs.produce_blocks }} + fund_status: ${{ needs.availability_test.outputs.fund_status }} + check_deployed_smart_contract_status: ${{ needs.availability_test.outputs.check_deployed_smart_contract_status }} + method_set_status: ${{ needs.availability_test.outputs.method_set_status }} + method_get_status: ${{ needs.availability_test.outputs.method_get_status }} + secrets: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/deploy-network.yml b/.github/workflows/deploy-network.yml index f528c9e813..931473d69e 100644 --- a/.github/workflows/deploy-network.yml +++ b/.github/workflows/deploy-network.yml @@ -93,6 +93,9 @@ on: # yamllint disable-line rule:truthy blade_healthcheck_output: description: Blade Healthcheck output value: ${{ jobs.deploy_network.outputs.blade_healthcheck_output }} + rpc_url: + description: RPC URL + value: ${{ jobs.check_network.outputs.rpc_url || jobs.deploy_network.outputs.rpc_url }} secrets: AWS_ROLE_ARN: required: true diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 1018169480..97d445e5ca 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -123,6 +123,9 @@ on: # yamllint disable-line rule:truthy txpool_queued: description: Queued Transactions Count value: ${{ jobs.txpool_status.outputs.txpool_queued }} + results_artifact_id: + description: Results Artifact ID + value: ${{ jobs.load_test.outputs.results_artifact_id }} secrets: AWS_ROLE_ARN: required: true @@ -194,7 +197,7 @@ jobs: github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} aws-resource-tags: > [ - {"Key": "Name", "Value": "LoadTestRunner"} + {"Key": "Name", "Value": "${{ inputs.environment }}-load-test-runner"} ] load_test: name: Run Load Test @@ -211,6 +214,7 @@ jobs: avg_gas_per_tx: ${{ steps.load_test_results.outputs.avg_gas_per_tx }} avg_gas_utilization: ${{ steps.load_test_results.outputs.avg_gas_utilization }} max_gas_utilization: ${{ steps.load_test_results.outputs.max_gas_utilization }} + results_artifact_id: ${{ steps.artifact-upload.outputs.artifact-id }} steps: - name: Checkout code uses: actions/checkout@v4.1.1 @@ -237,6 +241,13 @@ jobs: if: success() id: load_test_results_success run: echo "test_output=true" >> $GITHUB_OUTPUT + - name: Upload Artifact + uses: actions/upload-artifact@v4.3.0 + id: artifact-upload + with: + name: results_${{ inputs.type }}.tar.gz + path: results_${{ inputs.type }}.json + retention-days: 3 txpool_status: name: Check txpool status after Load Test runs-on: ubuntu-latest @@ -277,6 +288,7 @@ jobs: max_gas_utilization: ${{ needs.load_test.outputs.max_gas_utilization }} txpool_pending: ${{ needs.txpool_status.outputs.txpool_pending }} txpool_queued: ${{ needs.txpool_status.outputs.txpool_queued }} + results_url: ${{ needs.load_test.outputs.results_url }} secrets: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} destroy_load_test_runner: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6e69c45891..6827811498 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -36,6 +36,20 @@ jobs: AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} AWS_S3_BLADE_BUCKET: ${{ secrets.AWS_S3_BLADE_BUCKET }} VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }} + availability_tests: + name: Availability Tests + uses: ./.github/workflows/availability-tests.yml + needs: deploy_network + with: + environment: nightly + rpc_url: ${{ needs.deploy_network.outputs.rpc_url }} + fund_amount: "5" + london: true + notification: false + secrets: + FAUCET_PRIVATE_KEY: ${{ secrets.FAUCET_PRIVATE_KEY }} + ACCOUNT_PRIVATE_KEY: ${{ secrets.ACCOUNT_PRIVATE_KEY }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} sanity_check_tests: name: Sanity Check Tests uses: ./.github/workflows/sanity-check-test.yml @@ -49,7 +63,7 @@ jobs: load_test_eoa: name: Load Test EOA uses: ./.github/workflows/load-test.yml - needs: [deploy_network, sanity_check_tests] + needs: [deploy_network, availability_tests, sanity_check_tests] with: environment: nightly type: EOA @@ -73,7 +87,7 @@ jobs: load_test_erc20: name: Load Test ERC20 uses: ./.github/workflows/load-test.yml - needs: [deploy_network, sanity_check_tests, load_test_eoa] + needs: [deploy_network, availability_tests, sanity_check_tests, load_test_eoa] with: environment: nightly type: ERC20 @@ -97,7 +111,7 @@ jobs: load_test_erc721: name: Load Test ERC721 uses: ./.github/workflows/load-test.yml - needs: [deploy_network, sanity_check_tests, load_test_eoa, load_test_erc20] + needs: [deploy_network, availability_tests, sanity_check_tests, load_test_eoa, load_test_erc20] with: environment: nightly type: ERC721 @@ -121,7 +135,7 @@ jobs: load_test_mixed: name: Load Test MIXED uses: ./.github/workflows/load-test.yml - needs: [deploy_network, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721] + needs: [deploy_network, availability_tests, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721] with: environment: nightly type: MIXED @@ -145,7 +159,7 @@ jobs: destroy_network: name: Destroy Network uses: ./.github/workflows/destroy-network.yml - needs: [deploy_network, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721, load_test_mixed] + needs: [deploy_network, availability_tests, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721, load_test_mixed] if: always() with: environment: nightly @@ -158,7 +172,7 @@ jobs: notification_nightly: name: Nightly Notification uses: ./.github/workflows/notification-nightly.yml - needs: [ci, deploy_network, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721, load_test_mixed, destroy_network] + needs: [ci, deploy_network, availability_tests, sanity_check_tests, load_test_eoa, load_test_erc20, load_test_erc721, load_test_mixed, destroy_network] if: success() || failure() with: environment: nightly @@ -178,6 +192,7 @@ jobs: property_polybft_test_output: ${{ needs.ci.outputs.property_polybft_test }} fuzz_test_output: ${{ needs.ci.outputs.fuzz_test }} benchmark_test_output: ${{ needs.ci.outputs.benchmark_test }} + availability_test_status: ${{ needs.availability_tests.outputs.availability_test_status }} sanity_check_tests_output: ${{ needs.sanity_check_tests.outputs.sanity_check_tests_output }} stake_test_output: ${{ needs.sanity_check_tests.outputs.stake_test_output }} unstake_test_output: ${{ needs.sanity_check_tests.outputs.unstake_test_output }} @@ -230,6 +245,7 @@ jobs: max_gas_utilization: ${{ needs.load_test_eoa.outputs.max_gas_utilization }} txpool_pending: ${{ needs.load_test_eoa.outputs.txpool_pending }} txpool_queued: ${{ needs.load_test_eoa.outputs.txpool_queued }} + results_artifact_id: ${{ needs.load_test_eoa.outputs.results_artifact_id }} secrets: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} notification_load_test_erc20: @@ -258,6 +274,7 @@ jobs: max_gas_utilization: ${{ needs.load_test_erc20.outputs.max_gas_utilization }} txpool_pending: ${{ needs.load_test_erc20.outputs.txpool_pending }} txpool_queued: ${{ needs.load_test_erc20.outputs.txpool_queued }} + results_artifact_id: ${{ needs.load_test_erc20.outputs.results_artifact_id }} secrets: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} notification_load_test_erc721: @@ -286,6 +303,7 @@ jobs: max_gas_utilization: ${{ needs.load_test_erc721.outputs.max_gas_utilization }} txpool_pending: ${{ needs.load_test_erc721.outputs.txpool_pending }} txpool_queued: ${{ needs.load_test_erc721.outputs.txpool_queued }} + results_artifact_id: ${{ needs.load_test_erc721.outputs.results_artifact_id }} secrets: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} notification_load_test_mixed: @@ -314,5 +332,6 @@ jobs: max_gas_utilization: ${{ needs.load_test_mixed.outputs.max_gas_utilization }} txpool_pending: ${{ needs.load_test_mixed.outputs.txpool_pending }} txpool_queued: ${{ needs.load_test_mixed.outputs.txpool_queued }} + results_artifact_id: ${{ needs.load_test_mixed.outputs.results_artifact_id }} secrets: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/notification-availability-test.yml b/.github/workflows/notification-availability-test.yml new file mode 100644 index 0000000000..3274871678 --- /dev/null +++ b/.github/workflows/notification-availability-test.yml @@ -0,0 +1,108 @@ +--- +name: Notification - Availability Tests +on: # yamllint disable-line rule:truthy + workflow_call: + inputs: + environment: + type: string + required: true + availability_test_status: + type: string + required: true + produce_blocks: + type: string + required: true + fund_status: + type: string + required: true + check_deployed_smart_contract_status: + type: string + required: true + method_set_status: + type: string + required: true + method_get_status: + type: string + required: true + secrets: + SLACK_WEBHOOK_URL: + required: true + +jobs: + notification: + name: Notification + runs-on: ubuntu-latest + steps: + - name: Notify Slack + uses: slackapi/slack-github-action@v1.25.0 + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + succeed_bnt: 'primary' + failed_bnt: 'danger' + succeed_job: ':green:' + failed_job: ':red:' + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Availability Tests" + } + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "text": "Workflow Run" + }, + "style": "${{ inputs.availability_test_status == 'true' && env.succeed_bnt || env.failed_bnt }}", + "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + ] + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "Environment: *${{ inputs.environment }}*" + } + ] + }, + { + "type": "divider" + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "${{ inputs.produce_blocks == 'true' && env.succeed_job || env.failed_job }} *Produce Blocks*" + }, + { + "type": "mrkdwn", + "text": "${{ inputs.fund_status == 'true' && env.succeed_job || env.failed_job }} *Fund Account*" + }, + { + "type": "mrkdwn", + "text": "${{ inputs.check_deployed_smart_contract_status == 'true' && env.succeed_job || env.failed_job }} *Deploy Smart Contract*" + }, + { + "type": "mrkdwn", + "text": "${{ inputs.method_set_status == 'true' && env.succeed_job || env.failed_job }} *Method set()*" + }, + { + "type": "mrkdwn", + "text": "${{ inputs.method_get_status == 'true' && env.succeed_job || env.failed_job }} *Method get()*" + } + ] + } + ] + } diff --git a/.github/workflows/notification-load-test.yml b/.github/workflows/notification-load-test.yml index b7394daf0e..211ac690af 100644 --- a/.github/workflows/notification-load-test.yml +++ b/.github/workflows/notification-load-test.yml @@ -83,6 +83,10 @@ on: # yamllint disable-line rule:truthy description: Queued Transactions Count type: string required: true + results_artifact_id: + description: Results Artifact ID + type: string + required: true secrets: SLACK_WEBHOOK_URL: required: true @@ -125,6 +129,15 @@ jobs: }, "style": "${{ inputs.txpool_pending == '0' && inputs.txpool_queued == '0' && env.succeed_bnt || env.failed_bnt }}", "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + }, + { + "type": "button", + "text": { + "type": "plain_text", + "text": "${{ inputs.results_artifact_id != '' && 'Results' || 'No Results' }}" + }, + "style": "${{ inputs.results_artifact_id != '' && env.succeed_bnt || env.failed_bnt }}", + "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ inputs.results_artifact_id }}" } ] }, diff --git a/.github/workflows/notification-nightly.yml b/.github/workflows/notification-nightly.yml index 3f2b3a3f81..9479131038 100644 --- a/.github/workflows/notification-nightly.yml +++ b/.github/workflows/notification-nightly.yml @@ -71,6 +71,10 @@ on: # yamllint disable-line rule:truthy description: Benchmark Tests output type: string required: true + availability_test_status: + description: Availability Tests status + type: string + required: true sanity_check_tests_output: description: Sanity Check Tests output type: string @@ -340,6 +344,10 @@ jobs: { "type": "mrkdwn", "text": "${{ inputs.benchmark_test_output == '' && env.succeed_job || env.failed_job }} *Benchmark Tests*" + }, + { + "type": "mrkdwn", + "text": "${{ inputs.availability_test_status == 'true' && env.succeed_job || env.failed_job }} *Availability Tests*" } ] },