diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 61abaa2384..18620ea469 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -111,6 +111,7 @@ jobs: echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY build-test-image: + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') environment: integration permissions: id-token: write @@ -140,35 +141,46 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - eth-smoke-tests-matrix: + compare-tests: + needs: [changes] + runs-on: ubuntu-latest + name: Compare/Build Automation Test List + outputs: + matrix: ${{ env.MATRIX_JSON }} + steps: + - name: Checkout the repo + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - name: Compare Test Lists + run: | + cd ./integration-tests + ./scripts/compareTestList.sh ./smoke/automation_test.go + ./scripts/compareTestList.sh ./smoke/keeper_test.go + - name: Build Test Matrix Lists + id: build-test-matrix-list + run: | + cd ./integration-tests + MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB) + MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB) + COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") + echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + eth-smoke-tests-matrix-automation: environment: integration permissions: - issues: read checks: write pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes, build-test-image] + needs: [build-chainlink, changes, compare-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug - KEEP_ENVIRONMENTS: ONFAIL DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable strategy: fail-fast: false matrix: - product: - - name: automation - nodes: 19 - os: ubuntu-latest - pyroscope_env: ci-smoke-automation-evm-simulated - # temporarily disabled - # - name: ocr2vrf - # nodes: 2 - # os: ubuntu-latest - # pyroscope_env: ci-smoke-ocr2vrf-evm-simulated + product: ${{fromJson(needs.compare-tests.outputs.matrix)}} runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: @@ -176,23 +188,31 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Go Test Command + id: build-go-test-command + run: | + # if the matrix.product.run is set, use it for a different command + if [ "${{ matrix.product.run }}" != "" ]; then + echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT" + else + echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" + fi ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 env: - TESTCONTAINERS_RYUK_DISABLED: true PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ./smoke/${{ matrix.product.name }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_location: ./integration-tests/smoke/logs - publish_check_name: EVM Smoke Test Results ${{ matrix.product.name }} + publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} @@ -200,28 +220,6 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - ## Run this step when changes that do not need the test to run are made - - name: Run Setup - if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 - with: - test_download_vendor_packages_command: cd ./integration-tests && go mod download - go_mod_path: ./integration-tests/go.mod - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: 'true' - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - - name: Upload test log - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - if: failure() - with: - name: test-log-${{ matrix.product.name }} - path: /tmp/gotest.log - retention-days: 7 - continue-on-error: true - name: Collect Metrics if: always() id: collect-gha-metrics @@ -232,8 +230,7 @@ jobs: this-job-name: ETH Smoke Tests ${{ matrix.product.name }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - - eth-smoke-tests-matrix-docker: + eth-smoke-tests-matrix: environment: integration permissions: checks: write @@ -265,13 +262,12 @@ jobs: run: -run ^TestSmokeCCIPRateLimit$ - name: cron nodes: 1 - os: ubuntu20.04-8cores-32GB + os: ubuntu-latest + pyroscope_env: "" + - name: flux + nodes: 1 + os: ubuntu-latest pyroscope_env: "" -# Flakes -# - name: flux -# nodes: 1 -# os: ubuntu-latest -# pyroscope_env: "" - name: ocr nodes: 1 os: ubuntu20.04-8cores-32GB @@ -282,7 +278,7 @@ jobs: pyroscope_env: ci-smoke-ocr2-evm-simulated - name: runlog nodes: 1 - os: ubuntu20.04-8cores-32GB + os: ubuntu-latest pyroscope_env: "" - name: vrf nodes: 1 @@ -304,98 +300,6 @@ jobs: nodes: 1 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated - - # Keeper tests split out to use minimal environments -# - name: keeper-1 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperBasicSmoke$ -# - name: keeper-2 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperBlockCountPerTurn/registry_1_1$ -# - name: keeper-3 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperBlockCountPerTurn/registry_1_2$ -# - name: keeper-4 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperBlockCountPerTurn/registry_1_3$ -# - name: keeper-5 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperSimulation$ -# - name: keeper-6 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperCheckPerformGasLimit/registry_1_2$ -# - name: keeper-7 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperCheckPerformGasLimit/registry_1_3$ -# - name: keeper-8 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperRegisterUpkeep$ -# - name: keeper-9 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperAddFunds$ -# - name: keeper-10 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperRemove$ -# - name: keeper-11 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperPauseRegistry$ -# - name: keeper-12 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperMigrateRegistry$ -# - name: keeper-13 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperNodeDown/registry_1_1$ -# - name: keeper-14 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperNodeDown/registry_1_2$ -# - name: keeper-15 -# nodes: 1 -# os: ubuntu20.04-8cores-32GB -# pyroscope_env: ci-smoke-keeper-evm-simulated -# file: keeper -# run: -run ^TestKeeperNodeDown/registry_1_3$ runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: @@ -433,7 +337,7 @@ jobs: cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_location: ./integration-tests/smoke/logs - publish_check_name: EVM Smoke Test Results ${{ matrix.product.name }} + publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} @@ -473,16 +377,15 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - ### Used to check the required checks box when the matrix completes eth-smoke-tests: if: always() runs-on: ubuntu-latest name: ETH Smoke Tests - needs: [eth-smoke-tests-matrix,eth-smoke-tests-matrix-docker] + needs: [eth-smoke-tests-matrix, eth-smoke-tests-matrix-automation] steps: - name: Check smoke test matrix status - if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-docker.result != 'success' + if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-automation.result != 'success' run: exit 1 - name: Collect Metrics if: always() @@ -589,7 +492,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - ### Solana Section +# ### Solana Section # get_solana_sha: # name: Get Solana Sha From Go Mod # environment: Integration @@ -598,7 +501,7 @@ jobs: # sha: ${{ steps.getsha.outputs.sha }} # steps: # - name: Checkout the repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} # - name: Get the sha from go mod @@ -609,7 +512,7 @@ jobs: # echo "short sha is: ${short_sha}" # echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" # - name: Checkout solana -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # repository: smartcontractkit/chainlink-solana # ref: develop @@ -632,7 +535,7 @@ jobs: # projectserum_version: ${{ steps.psversion.outputs.projectserum_version }} # steps: # - name: Checkout the solana repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # repository: smartcontractkit/chainlink-solana # ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -694,7 +597,7 @@ jobs: # this-job-name: Solana Build Artifacts # continue-on-error: true # - name: Checkout the solana repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # repository: smartcontractkit/chainlink-solana # ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -724,7 +627,7 @@ jobs: # CONTRACT_ARTIFACTS_PATH: contracts/target/deploy # steps: # - name: Collect Metrics -# if: needs.changes.outputs.src == 'true' +# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' # id: collect-gha-metrics # uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec # with: @@ -733,7 +636,8 @@ jobs: # this-job-name: Solana Build Test Image # continue-on-error: true # - name: Checkout the repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # repository: smartcontractkit/chainlink-solana # ref: 23816fcf7d380a30c87b6d87e4fb0ca94419b259 # swtich back to this after the next solana release${{ needs.get_solana_sha.outputs.sha }} @@ -746,6 +650,8 @@ jobs: # QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} # QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} # QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} +# - run: echo "this exists so we don't have to run anything else if the build is skipped" +# if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' # # solana-smoke-tests: # environment: integration @@ -788,7 +694,7 @@ jobs: # test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' # continue-on-error: true # - name: Checkout the repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # repository: smartcontractkit/chainlink-solana # ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -827,7 +733,7 @@ jobs: # pull-requests: write # id-token: write # contents: read -# needs: [build-chainlink, build-test-image] +# needs: [build-chainlink] # env: # SELECTED_NETWORKS: ${{ matrix.testnet }} # CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -836,11 +742,11 @@ jobs: # EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} # TEST_EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} # -# TEST_OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} -# TEST_OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} +# OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} +# OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} # -# TEST_ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} -# TEST_ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} +# ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} +# ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} # strategy: # fail-fast: false # matrix: @@ -852,7 +758,7 @@ jobs: # runs-on: ubuntu-latest # steps: # - name: Checkout the repo -# uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 +# uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # with: # ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} # ## Only run OCR smoke test for now @@ -1011,4 +917,4 @@ jobs: # env: # SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} # -# ### End Live Testnet Section +# ### End Live Testnet Section \ No newline at end of file diff --git a/integration-tests/Makefile b/integration-tests/Makefile index c1fa146cea..110c119df7 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -2,43 +2,42 @@ BIN_DIR = bin export GOPATH ?= $(shell go env GOPATH) export GO111MODULE ?= on -LINUX = LINUX -OSX = OSX -WINDOWS = WIN32 -OSFLAG := +LINUX=LINUX +OSX=OSX +WINDOWS=WIN32 +OSFLAG := ifeq ($(OS),Windows_NT) - OSFLAG = $(WINDOWS) + OSFLAG = $(WINDOWS) else - UNAME_S := $(shell uname -s) - + UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) - OSFLAG = $(LINUX) + OSFLAG = $(LINUX) endif - ifeq ($(UNAME_S),Darwin) - OSFLAG = $(OSX) + OSFLAG = $(OSX) endif endif - install_qa_tools: ifeq ($(OSFLAG),$(WINDOWS)) echo "If you are running windows and know how to install what is needed, please contribute by adding it here!" echo "You will need nodejs, golang, k3d, and helm." exit 1 -endif +else + +# linux and mac can use asdf to install all of the dependencies +ifeq ($(shell which asdf), ) # install asdf -ifeq ($(shell which asdf),) ifeq ($(OSFLAG),$(LINUX)) echo "You will need to install asdf via your linux installer https://asdf-vm.com/guide/getting-started.html" exit 1 -endif +else ifeq ($(OSFLAG),$(OSX)) brew install asdf endif endif - +endif # install the plugins if needed and then install the dependencies asdf plugin-add nodejs || true asdf plugin-add golang || true @@ -46,13 +45,12 @@ endif asdf plugin-add helm || true asdf plugin-add kubectl || true asdf install - +endif # Now install the helm charts that are needed (should be os agnostic) helm repo add chainlink-qa https://raw.githubusercontent.com/smartcontractkit/qa-charts/gh-pages/ helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update - .PHONY: install_gotestfmt install_gotestfmt: go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest @@ -70,11 +68,7 @@ build_test_image: #Build a chainlink docker image for local testing and push to k3d registry .PHONY: build_push_docker_image build_push_docker_image: - docker build -f ../core/chainlink.Dockerfile \ - --build-arg COMMIT_SHA=$(shell git rev-parse HEAD) \ - --build-arg CHAINLINK_USER=chainlink \ - -t localhost:5000/chainlink:develop ../ - docker push localhost:5000/chainlink:develop + docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop ## Test Runner .PHONY: run @@ -135,16 +129,6 @@ test_chaos_network: install_gotestfmt ## Run all smoke tests test_chaos_verbose: ## Run all smoke tests with verbose logging go test -timeout 24h -count=1 -v $(args) ./chaos -.PHONY: test_chaos_ccip_pods_raw -test_chaos_ccip_pods_raw: - DATABASE_URL="postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable" \ - go test -timeout 2h -v -count=1 $(args) -p 2 -run 'TestChaosCCIP/.*pod-chaos' ./chaos - -.PHONY: test_chaos_ccip_network_raw -test_chaos_ccip_network_raw: - DATABASE_URL="postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable" \ - go test -timeout 2h -v -count=1 $(args) -p 2 -run 'TestChaosCCIP/.*network-chaos' ./chaos - # Performance .PHONY: test_perf test_perf: test_need_operator_assets ## Run core node performance tests. @@ -208,16 +192,13 @@ test_benchmark_automation: ## Run the automation benchmark tests test_reorg_automation: ## Run the automation reorg tests go test -timeout 300m -v -run ^TestAutomationReorg$$ ./reorg -count=1 | tee automation_reorg_run_`date +"%Y%m%d-%H%M%S"`.log - # image: the name for the chainlink image being built, example: image=chainlink # tag: the tag for the chainlink image being built, example: tag=latest # example usage: make build_docker_image image=chainlink tag=latest .PHONY: build_docker_image build_docker_image: - docker build -f ../core/chainlink.Dockerfile \ - --build-arg COMMIT_SHA=$(git rev-parse HEAD) \ - --build-arg CHAINLINK_USER=chainlink \ - -t $(image):$(tag) ../ + docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t $(image):$(tag) ../ + # image: the name for the chainlink image being built, example: image=chainlink # tag: the tag for the chainlink image being built, example: tag=latest @@ -231,4 +212,4 @@ run_test_with_local_image: build_docker_image SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ ARGS="$(args)" \ PRODUCT=$(product) \ - ./scripts/run_product_tests + ./scripts/run_product_tests \ No newline at end of file diff --git a/integration-tests/README.md b/integration-tests/README.md index ea252313d2..3a2a59e0fb 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -52,7 +52,6 @@ increase minikube's resources significantly, or get a more substantial cluster. This is necessary to deploy ephemeral testing environments, which include external adapters, chainlink nodes and their DBs, as well as some simulated blockchains, all depending on the types of tests and networks being used. - ### Setup Kubernetes Cluster using k3d [k3d](https://k3d.io/) is a lightweight wrapper to run k3s (a lightweight kubernetes distribution) in docker. It's a great way to run a local kubernetes cluster for testing. @@ -91,6 +90,7 @@ You can also specify `EVM_KEYS` and `EVM_URLS` for running on live chains, or us Other `EVM_*` variables are retrieved when running with the `@general` tag, and is helpful for doing quick sanity checks on new chains or when tweaking variables. **The tests will not automatically load your .env file. Remember to run `source .env` for changes to take effect.** + ## How to Run Most of the time, you'll want to run tests on a simulated chain, for the purposes of speed and cost. @@ -186,71 +186,6 @@ Currently, all performance tests are only run on simulated blockchains. make test_perf ``` -## CCIP Tests - -### Configure Environment for CCIP - -> CCIP tests follow some additional set up as it needs multi-chain set-up to run the tests. -> To run any kind of CCIP tests you need to provide the some mandatory and optional env variables. -> See the [ccip-example.env](ccip/ccip-example.env) file and use it as a template for your own .env file. -> The tests will not automatically load your .env file. Remember to run source .env for changes to take effect. - - - -### How to Run CCIP Tests - ->After following the instructions [Install Dependencies](#setup) , [K8 Setup](#connect-to-a-kubernetes-cluster) ->and [Configure Environment](#configure-environment-for-ccip) , you can run the tests using the following commands. - -#### Smoke tests -Mostly you would run tests on simulated networks for cost and speed- -```sh -make test_smoke_ccip_simulated -``` -On specific networks (set up according to envionment variables) - -```sh -make test_smoke_ccip -``` - -#### Load tests -On simulated networks - -```sh -make test_load_ccip_simulated -``` -On specific networks (set up according to envionment variables) - -```sh -make test_load_ccip -``` - -#### Soak tests -Soak tests are just load tests run with long duration and lesser rate of request triggering. -```sh -make test_soak_ccip -``` - -#### Chaos tests -Chaos tests can only be run in simulated networks to inject specific chaos events in custom environments. -You need to trigger podchaos tests and network chaos tests separately. - -```sh -make test_chaos_ccip_pods_raw -``` - -```sh -make test_chaos_ccip_network_raw -``` -#### Soak/Load/Smoke tests on Existing Deployments -> Tests can be run on existing deployments by setting the env var CCIP_TESTS_ON_EXISTING_DEPLOYMENT to true. -> 1. Create a branch out of the code ref using which the contracts were deployed. (This is to ensure that the gethwrappers are compatible with the deployed contracts) -> 2. Update [contracts.json](ccip/contracts/laneconfig/contracts.json) file with the contract addresses of the deployment under test. -> 3. Set the env var CCIP_TESTS_ON_EXISTING_DEPLOYMENT to true in the .env file. -> 4. Set up other env vars denoting the network and other load config parameters in .env file as mentioned in [Configure Environment](#configure-environment-for-ccip) section. -> 5. Run the tests in same branch using the following command - -> ```sh -> source -> make test_soak_ccip # Or the corresponding make _test command for load or smoke tests -> ``` - ## Common Issues - When upgrading to a new version, it's possible the helm charts have changed. There are a myriad of errors that can result from this, so it's best to just try running `helm repo update` when encountering an error you're unsure of. diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go new file mode 100644 index 0000000000..d2e2fde321 --- /dev/null +++ b/integration-tests/actions/actions_local.go @@ -0,0 +1,25 @@ +// Package actions enables common chainlink interactions +package actions + +import ( + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" +) + +// UpgradeChainlinkNodeVersions upgrades all Chainlink nodes to a new version, and then runs the test environment +// to apply the upgrades +func UpgradeChainlinkNodeVersionsLocal( + newImage, newVersion string, + nodes ...*test_env.ClNode, +) error { + if newImage == "" && newVersion == "" { + return errors.New("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") + } + for _, node := range nodes { + if err := node.UpgradeVersion(node.NodeConfig, newImage, newVersion); err != nil { + return err + } + } + return nil +} diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go new file mode 100644 index 0000000000..dce55e4227 --- /dev/null +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -0,0 +1,258 @@ +package actions + +//revive:disable:dot-imports +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" + ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +func BuildAutoOCR2ConfigVarsLocal( + t *testing.T, + chainlinkNodes []*client.ChainlinkClient, + registryConfig contracts.KeeperRegistrySettings, + registrar string, + deltaStage time.Duration, +) (contracts.OCRv2Config, error) { + return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(t, chainlinkNodes, registryConfig, registrar, deltaStage, 0) +} + +func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( + t *testing.T, + chainlinkNodes []*client.ChainlinkClient, + registryConfig contracts.KeeperRegistrySettings, + registrar string, + deltaStage time.Duration, + keyIndex int, +) (contracts.OCRv2Config, error) { + l := utils.GetTestLogger(t) + S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndexLocal(chainlinkNodes, keyIndex) + if err != nil { + return contracts.OCRv2Config{}, err + } + + var offC []byte + var signerOnchainPublicKeys []types.OnchainPublicKey + var transmitterAccounts []types.Account + var f uint8 + var offchainConfigVersion uint64 + var offchainConfig []byte + + if registryConfig.RegistryVersion == ethereum.RegistryVersion_2_1 { + offC, err = json.Marshal(ocr2keepers30config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 3600000, // Intentionally set to be higher than in prod for testing purpose + GasLimitPerReport: 5_300_000, + GasOverheadPerUpkeep: 300_000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 1, + }) + if err != nil { + return contracts.OCRv2Config{}, err + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr3.ContractSetConfigArgsForTests( + 10*time.Second, // deltaProgress time.Duration, + 15*time.Second, // deltaResend time.Duration, + 500*time.Millisecond, // deltaInitial time.Duration, + 1000*time.Millisecond, // deltaRound time.Duration, + 200*time.Millisecond, // deltaGrace time.Duration, + 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration + deltaStage, // deltaStage time.Duration, + 24, // rMax uint64, + S, // s []int, + oracleIdentities, // oracles []OracleIdentityExtra, + offC, // reportingPluginConfig []byte, + 20*time.Millisecond, // maxDurationQuery time.Duration, + 20*time.Millisecond, // maxDurationObservation time.Duration, // good to here + 1200*time.Millisecond, // maxDurationShouldAcceptAttestedReport time.Duration, + 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, + 1, // f int, + nil, // onchainConfig []byte, + ) + if err != nil { + return contracts.OCRv2Config{}, err + } + } else { + offC, err = json.Marshal(ocr2keepers20config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 3600000, // Intentionally set to be higher than in prod for testing purpose + GasLimitPerReport: 5_300_000, + GasOverheadPerUpkeep: 300_000, + SamplingJobDuration: 3000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 1, + }) + if err != nil { + return contracts.OCRv2Config{}, err + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr2.ContractSetConfigArgsForTests( + 10*time.Second, // deltaProgress time.Duration, + 15*time.Second, // deltaResend time.Duration, + 3000*time.Millisecond, // deltaRound time.Duration, + 200*time.Millisecond, // deltaGrace time.Duration, + deltaStage, // deltaStage time.Duration, + 24, // rMax uint8, + S, // s []int, + oracleIdentities, // oracles []OracleIdentityExtra, + offC, // reportingPluginConfig []byte, + 20*time.Millisecond, // maxDurationQuery time.Duration, + 20*time.Millisecond, // maxDurationObservation time.Duration, + 1200*time.Millisecond, // maxDurationReport time.Duration, + 20*time.Millisecond, // maxDurationShouldAcceptFinalizedReport time.Duration, + 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, + 1, // f int, + nil, // onchainConfig []byte, + ) + if err != nil { + return contracts.OCRv2Config{}, err + } + } + + var signers []common.Address + for _, signer := range signerOnchainPublicKeys { + require.Equal(t, 20, len(signer), "OnChainPublicKey '%v' has wrong length for address", signer) + signers = append(signers, common.BytesToAddress(signer)) + } + + var transmitters []common.Address + for _, transmitter := range transmitterAccounts { + require.True(t, common.IsHexAddress(string(transmitter)), "TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + } + + onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar) + if err != nil { + return contracts.OCRv2Config{}, err + } + + l.Info().Msg("Done building OCR config") + return contracts.OCRv2Config{ + Signers: signers, + Transmitters: transmitters, + F: f, + OnchainConfig: onchainConfig, + OffchainConfigVersion: offchainConfigVersion, + OffchainConfig: offchainConfig, + }, nil +} + +// CreateOCRKeeperJobs bootstraps the first node and to the other nodes sends ocr jobs +func CreateOCRKeeperJobsLocal( + chainlinkNodes []*client.ChainlinkClient, + registryAddr string, + chainID int64, + keyIndex int, + registryVersion ethereum.KeeperRegistryVersion, +) error { + bootstrapNode := chainlinkNodes[0] + bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() + if err != nil { + log.Error().Err(err).Msg("Shouldn't fail reading P2P keys from bootstrap node") + return err + } + bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID + + var contractVersion string + if registryVersion == ethereum.RegistryVersion_2_1 { + contractVersion = "v2.1" + } else if registryVersion == ethereum.RegistryVersion_2_0 { + contractVersion = "v2.0" + } else { + return errors.New("v2.0 and v2.1 are the only supported versions") + } + + bootstrapSpec := &client.OCR2TaskJobSpec{ + Name: "ocr2 bootstrap node " + registryAddr, + JobType: "bootstrap", + OCR2OracleSpec: job.OCR2OracleSpec{ + ContractID: registryAddr, + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(chainID), + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + }, + } + _, err = bootstrapNode.MustCreateJob(bootstrapSpec) + if err != nil { + log.Error().Err(err).Msg("Shouldn't fail creating bootstrap job on bootstrap node") + return err + } + + P2Pv2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PId, bootstrapNode.InternalIP(), 6690) + for nodeIndex := 1; nodeIndex < len(chainlinkNodes); nodeIndex++ { + nodeTransmitterAddress, err := chainlinkNodes[nodeIndex].EthAddresses() + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail getting primary ETH address from OCR node %d", nodeIndex+1) + return err + } + nodeOCRKeys, err := chainlinkNodes[nodeIndex].MustReadOCR2Keys() + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail getting OCR keys from OCR node %d", nodeIndex+1) + return err + } + var nodeOCRKeyId []string + for _, key := range nodeOCRKeys.Data { + if key.Attributes.ChainType == string(chaintype.EVM) { + nodeOCRKeyId = append(nodeOCRKeyId, key.ID) + break + } + } + + autoOCR2JobSpec := client.OCR2TaskJobSpec{ + Name: "ocr2 " + registryAddr, + JobType: "offchainreporting2", + OCR2OracleSpec: job.OCR2OracleSpec{ + PluginType: "ocr2automation", + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(chainID), + }, + PluginConfig: map[string]interface{}{ + "mercuryCredentialName": "\"cred1\"", + "contractVersion": "\"" + contractVersion + "\"", + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + ContractID: registryAddr, // registryAddr + OCRKeyBundleID: null.StringFrom(nodeOCRKeyId[0]), // get node ocr2config.ID + TransmitterID: null.StringFrom(nodeTransmitterAddress[keyIndex]), // node addr + P2PV2Bootstrappers: pq.StringArray{P2Pv2Bootstrapper}, // bootstrap node key and address @bootstrap:8000 + }, + } + + _, err = chainlinkNodes[nodeIndex].MustCreateJob(&autoOCR2JobSpec) + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail creating OCR Task job on OCR node %d err: %+v", nodeIndex+1, err) + return err + } + + } + log.Info().Msg("Done creating OCR automation jobs") + return nil +} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 6ce0fb7138..fbabfab78c 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 0da3271785..bb7fe1b8f0 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 7d10107ba5..91c9084d40 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -18,13 +18,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) func TestOCR2VRFChaos(t *testing.T) { diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 58b4d5bea6..1e5b845145 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -22,11 +22,12 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 7517ef7ba7..2c079a61b8 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,7 @@ package contracts import ( "errors" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -12,6 +13,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // ContractLoader is an interface for abstracting the contract loading methods across network implementations @@ -24,6 +27,10 @@ type ContractLoader interface { LoadFunctionsCoordinator(addr string) (FunctionsCoordinator, error) LoadFunctionsRouter(addr string) (FunctionsRouter, error) LoadFunctionsLoadTestClient(addr string) (FunctionsLoadTestClient, error) + + // Mercury + LoadMercuryVerifier(addr string) (MercuryVerifier, error) + LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) } // NewContractLoader returns an instance of a contract Loader based on the client type @@ -189,3 +196,39 @@ func (e *EthereumContractLoader) LoadAuthorizedForwarder(address common.Address) authorizedForwarder: instance.(*authorized_forwarder.AuthorizedForwarder), }, err } + +// LoadMercuryVerifier returns Verifier contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifier(addr string) (MercuryVerifier, error) { + instance, err := e.client.LoadContract("Mercury Verifier", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier.NewVerifier(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifier{ + client: e.client, + instance: instance.(*verifier.Verifier), + address: common.HexToAddress(addr), + }, err +} + +// LoadMercuryVerifierProxy returns VerifierProxy contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) { + instance, err := e.client.LoadContract("Mercury Verifier Proxy", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier_proxy.NewVerifierProxy(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifierProxy{ + client: e.client, + instance: instance.(*verifier_proxy.VerifierProxy), + address: common.HexToAddress(addr), + }, err +} diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 8e9d561f82..7bcddceae5 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -367,3 +367,14 @@ type FunctionsLoadTestClient interface { SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error } + +type MercuryVerifier interface { + Address() string + Verify(signedReport []byte, sender common.Address) error +} + +type MercuryVerifierProxy interface { + Address() string + Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) + VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) +} diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 5e937ad9b7..763faecace 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -46,6 +46,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // EthereumOracle oracle for "directrequest" job tests @@ -2244,3 +2246,65 @@ func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times } return e.client.ProcessTransaction(tx) } + +type EthereumMercuryVerifier struct { + address common.Address + client blockchain.EVMClient + instance *verifier.Verifier +} + +func (e *EthereumMercuryVerifier) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifier) Verify(signedReport []byte, sender common.Address) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := e.instance.Verify(opts, signedReport, sender) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +type EthereumMercuryVerifierProxy struct { + address common.Address + client blockchain.EVMClient + instance *verifier_proxy.VerifierProxy +} + +func (e *EthereumMercuryVerifierProxy) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifierProxy) Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.Verify(opts, signedReport) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *EthereumMercuryVerifierProxy) VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.VerifyBulk(opts, signedReports) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index e4279c8bce..67d2696058 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -76,6 +76,7 @@ type KeeperRegistry interface { PauseUpkeep(id *big.Int) error UnpauseUpkeep(id *big.Int) error UpdateCheckData(id *big.Int, newCheckData []byte) error + SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error } type KeeperConsumer interface { @@ -903,6 +904,26 @@ func (v *EthereumKeeperRegistry) UpdateCheckData(id *big.Int, newCheckData []byt } } +// SetUpkeepTriggerConfig updates the trigger config of an upkeep (only for version 2.1) +func (v *EthereumKeeperRegistry) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error { + + switch v.version { + case ethereum.RegistryVersion_2_1: + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + + tx, err := v.registry2_1.SetUpkeepTriggerConfig(opts, id, triggerConfig) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) + default: + return fmt.Errorf("SetUpkeepTriggerConfig is not supported by keeper registry version %d", v.version) + } +} + // PauseUpkeep stops an upkeep from an upkeep func (v *EthereumKeeperRegistry) PauseUpkeep(id *big.Int) error { switch v.version { diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index b665839f9c..4c2213b03e 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -46,6 +46,8 @@ type ClNode struct { NodeSecretsConfigTOML string PostgresDb *test_env.PostgresDb lw *logwatch.LogWatch + ContainerImage string + ContainerVersion string } type ClNodeOption = func(c *ClNode) @@ -101,6 +103,19 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { return n.StartContainer() } +// UpgradeVersion restarts the cl node with new image and version +func (n *ClNode) UpgradeVersion(cfg *chainlink.Config, newImage, newVersion string) error { + if newVersion == "" { + return fmt.Errorf("new version is empty") + } + if newImage == "" { + newImage = os.Getenv("CHAINLINK_IMAGE") + } + n.ContainerImage = newImage + n.ContainerVersion = newVersion + return n.Restart(n.NodeConfig) +} + func (n *ClNode) PrimaryETHAddress() (string, error) { return n.API.PrimaryEthAddress() } @@ -203,7 +218,6 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { } return evmClient.Fund(toAddress, amount, gasEstimates) } - func (n *ClNode) StartContainer() error { err := n.PostgresDb.StartContainer() if err != nil { @@ -226,6 +240,7 @@ func (n *ClNode) StartContainer() error { container, err := tc.GenericContainer(context.Background(), tc.GenericContainerRequest{ ContainerRequest: *cReq, Started: true, + Reuse: true, }) if err != nil { return errors.Wrap(err, ErrStartCLNodeContainer) @@ -312,18 +327,24 @@ func (n *ClNode) getContainerRequest() ( adminCredsPath := "/home/admin-credentials.txt" apiCredsPath := "/home/api-credentials.txt" - image, ok := os.LookupEnv("CHAINLINK_IMAGE") - if !ok { - return nil, errors.New("CHAINLINK_IMAGE env must be set") + if n.ContainerImage == "" { + image, ok := os.LookupEnv("CHAINLINK_IMAGE") + if !ok { + return nil, errors.New("CHAINLINK_IMAGE env must be set") + } + n.ContainerImage = image } - tag, ok := os.LookupEnv("CHAINLINK_VERSION") - if !ok { - return nil, errors.New("CHAINLINK_VERSION env must be set") + if n.ContainerVersion == "" { + version, ok := os.LookupEnv("CHAINLINK_VERSION") + if !ok { + return nil, errors.New("CHAINLINK_VERSION env must be set") + } + n.ContainerVersion = version } return &tc.ContainerRequest{ Name: n.ContainerName, - Image: fmt.Sprintf("%s:%s", image, tag), + Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), ExposedPorts: []string{"6688/tcp"}, Entrypoint: []string{"chainlink", "-c", configPath, diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 2d61da4010..e90bf5618a 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -8,17 +8,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/rs/zerolog/log" + tc "github.com/testcontainers/testcontainers-go" + "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" - tc "github.com/testcontainers/testcontainers-go" - "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker" "github.com/smartcontractkit/chainlink/integration-tests/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) var ( diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index a4e06a1b80..7726c115ff 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -10,11 +10,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) @@ -135,7 +135,6 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e return nil, err } } - if b.nonDevGethNetworks != nil { te.WithPrivateGethChain(b.nonDevGethNetworks) err := te.StartPrivateGethChain() @@ -187,29 +186,6 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e } te.ContractLoader = cl - if b.nonDevGethNetworks != nil { - te.WithPrivateGethChain(b.nonDevGethNetworks) - err := te.StartPrivateGethChain() - if err != nil { - return te, err - } - var nonDevGethNetworks []blockchain.EVMNetwork - for i, n := range te.PrivateGethChain { - nonDevGethNetworks = append(nonDevGethNetworks, *n.NetworkConfig) - nonDevGethNetworks[i].URLs = []string{n.PrimaryNode.InternalWsUrl} - nonDevGethNetworks[i].HTTPURLs = []string{n.PrimaryNode.InternalHttpUrl} - } - if nonDevGethNetworks == nil { - return nil, errors.New("cannot create nodes with custom config without nonDevGethNetworks") - } - - err = te.StartClNodes(b.clNodeConfig, b.clNodesCount) - if err != nil { - return nil, err - } - return te, nil - } - var nodeCsaKeys []string // Start Chainlink Nodes diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 018b1b3011..6be2c61a16 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -21,7 +21,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chain-selectors v1.0.1 github.com/smartcontractkit/chainlink-env v0.36.0 - github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230907234215-8f758ef3a2d9 + github.com/smartcontractkit/chainlink-testing-framework v1.16.6 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20230828183543-6d0939746966 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 @@ -42,6 +42,13 @@ require ( gopkg.in/guregu/null.v4 v4.0.0 ) +// Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them +replace ( + k8s.io/api => k8s.io/api v0.25.11 + k8s.io/client-go => k8s.io/client-go v0.25.11 + k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d +) + require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect @@ -521,9 +528,6 @@ replace ( github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 github.com/sercand/kuberesolver v2.4.0+incompatible => github.com/sercand/kuberesolver/v5 v5.1.0 - github.com/smartcontractkit/chainlink/integration-tests => ../integration-tests - k8s.io/api => k8s.io/api v0.25.11 - k8s.io/client-go => k8s.io/client-go v0.25.11 - k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d + github.com/smartcontractkit/chainlink/integration-tests => ../integration-tests ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index c74f17ccb0..a008cd1111 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2278,8 +2278,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97ac github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230907234215-8f758ef3a2d9 h1:cd7KmW4wY7AsqwVCl5W4pmVA6iimSkuX7fObRHUhtxs= -github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230907234215-8f758ef3a2d9/go.mod h1:Ry6fRPr8TwrIsYVNEF1pguAgzE3QW1s54tbLWnFtfI4= +github.com/smartcontractkit/chainlink-testing-framework v1.16.6 h1:TYMlPCj5xXJd2gz0n8SzZ8aSkxdEhsgg8exjmgMz9Oc= +github.com/smartcontractkit/chainlink-testing-framework v1.16.6/go.mod h1:Ry6fRPr8TwrIsYVNEF1pguAgzE3QW1s54tbLWnFtfI4= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= diff --git a/integration-tests/load/README.md b/integration-tests/load/README.md new file mode 100644 index 0000000000..1ed1ee8b94 --- /dev/null +++ b/integration-tests/load/README.md @@ -0,0 +1,63 @@ +## Performance tests for CL jobs + +This folder container performance e2e tests for different job types, currently implemented: +- VRFv2 + +All the tests have 4 groups: +- one product soak +- one product load +- multiple product instances soak +- multiple product instances load + +When you develop an e2e performance suite for a new product you can implement the tests one by one to answer the questions: + +What are performance characteristics of a one instance of a product (jobs + contracts): +- is our product stable at all, no memory leaks, no flaking performance under some RPS? (test #1) +- what are the limits for one product instance, figuring out the max/optimal performance params by increasing RPS and varying configuration (test #2) +- update test #1 with optimal params and workload to constantly run in CI + +What are performance and capacity characteristics of Chainlink node(s) that run multiple products of the same type simultaneously: +- how many products of the same type we can run at once at a stable load with optimal configuration? (test #3) +- what are the limits if we add more and more products of the same type, each product have a stable RPS, we vary only amount of products +- update test #3 with optimal params and workload to constantly run in CI + +Implementing test #1 is **mandatory** for each product. +Tests #2,#3,#4 are optional if you need to figure out your product scaling or node/cluster capacity. + + +## Usage +``` +export LOKI_TOKEN=... +export LOKI_URL=... + +go test -v -run TestVRFV2Load/vrfv2_soak_test +``` + +### Dashboards +Each product has its own generated dashboard in `cmd/dashboard.go` + +Deploying dashboard: +``` +export GRAFANA_URL=... +export GRAFANA_TOKEN=... +export DATA_SOURCE_NAME=grafanacloud-logs +export DASHBOARD_FOLDER=LoadTests +export DASHBOARD_NAME=${JobTypeName, for example WaspVRFv2} + +go run dashboard.go +``` + +### Assertions + +You can implement your product requirements assertions in `onchain_monitoring.go`. For Chainlink products (VRF/OCR/Keepers/Automation) it's easier to assert on-chain part + +If you need to assert some metrics in `Prometheus/Loki`, here is an [example](https://github.com/smartcontractkit/wasp/blob/master/examples/alerts/main_test.go#L88) + +Do not mix workload logic with assertions, separate them. + +### Implementation +To implement a standard e2e performance suite for a new product please look at `gun.go` and `vu.go`. + +Gun should be working with one instance of your product. + +VU(Virtual user) creates a new instance of your product and works with it in `Call()` \ No newline at end of file diff --git a/integration-tests/load/functions/README.md b/integration-tests/load/functions/README.md index 6b80137cf4..d9eb9cc1ef 100644 --- a/integration-tests/load/functions/README.md +++ b/integration-tests/load/functions/README.md @@ -13,21 +13,37 @@ See more config options in [config.toml](./config.toml) ## Usage -Soak `1 TX/sec - 40 requests per TX` -``` -go test -v -run TestFunctionsLoad/functions_soak_test -``` -Stress `1 TX/sec - 78 requests per TX` (max gas) -``` -go test -v -run TestFunctionsLoad/functions_stress_test -``` -Gateway `secrets_list` test +All tests are split by network and in 3 groups: +- HTTP payload only +- Secrets decoding payload only +- Realistic payload with args/http/secrets + +Load test client is [here](../../../contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol) + +Load is controlled with 2 params: +- RPS +- requests_per_call (generating more events in a loop in the contract) + +`Soak` is a stable workload for which there **must** be no issues + +`Stress` is a peak workload for which issues **must** be analyzed + +Load test client can execute `78 calls per request` at max (gas limit) + +Functions tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_real +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_real ``` -Gateway `secrets_set` test + +Gateway tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_set_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_set_soak_test ``` Chaos suite can be combined with any test, can be found [here](../../chaos/functions/full.yaml) diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index b18549f460..5c622401ab 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -18,7 +18,11 @@ const ( type PerformanceConfig struct { Soak *Soak `toml:"Soak"` + SecretsSoak *SecretsSoak `toml:"SecretsSoak"` + RealSoak *RealSoak `toml:"RealSoak"` Stress *Stress `toml:"Stress"` + SecretsStress *SecretsStress `toml:"SecretsStress"` + RealStress *RealStress `toml:"RealStress"` GatewayListSoak *GatewayListSoak `toml:"GatewayListSoak"` GatewaySetSoak *GatewaySetSoak `toml:"GatewaySetSoak"` Common *Common `toml:"Common"` @@ -27,18 +31,21 @@ type PerformanceConfig struct { type Common struct { Funding - LINKTokenAddr string `toml:"link_token_addr"` - Coordinator string `toml:"coordinator_addr"` - Router string `toml:"router_addr"` - LoadTestClient string `toml:"client_addr"` - SubscriptionID uint64 `toml:"subscription_id"` - DONID string `toml:"don_id"` - GatewayURL string `toml:"gateway_url"` - Receiver string `toml:"receiver"` - FunctionsCallPayload string `toml:"functions_call_payload"` - Secrets string `toml:"secrets"` - SecretsSlotID uint8 `toml:"secrets_slot_id"` - SecretsVersionID uint64 `toml:"secrets_version_id"` + LINKTokenAddr string `toml:"link_token_addr"` + Coordinator string `toml:"coordinator_addr"` + Router string `toml:"router_addr"` + LoadTestClient string `toml:"client_addr"` + SubscriptionID uint64 `toml:"subscription_id"` + DONID string `toml:"don_id"` + GatewayURL string `toml:"gateway_url"` + Receiver string `toml:"receiver"` + FunctionsCallPayloadHTTP string `toml:"functions_call_payload_http"` + FunctionsCallPayloadWithSecrets string `toml:"functions_call_payload_with_secrets"` + FunctionsCallPayloadReal string `toml:"functions_call_payload_real"` + SecretsSlotID uint8 `toml:"secrets_slot_id"` + SecretsVersionID uint64 `toml:"secrets_version_id"` + // Secrets these are for CI secrets + Secrets string `toml:"secrets"` } type Funding struct { @@ -52,12 +59,36 @@ type Soak struct { Duration *models.Duration `toml:"duration"` } +type SecretsSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type Stress struct { RPS int64 `toml:"rps"` RequestsPerCall uint32 `toml:"requests_per_call"` Duration *models.Duration `toml:"duration"` } +type SecretsStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type GatewayListSoak struct { RPS int64 `toml:"rps"` Duration *models.Duration `toml:"duration"` diff --git a/integration-tests/load/functions/config.toml b/integration-tests/load/functions/config.toml index f31342f013..2de3ba9282 100644 --- a/integration-tests/load/functions/config.toml +++ b/integration-tests/load/functions/config.toml @@ -8,6 +8,26 @@ rps = 1 requests_per_call = 78 duration = "10m" +[SecretsSoak] +rps = 1 +requests_per_call = 20 +duration = "10m" + +[SecretsStress] +rps = 1 +requests_per_call = 40 +duration = "10m" + +[RealSoak] +rps = 1 +requests_per_call = 20 +duration = "10m" + +[RealStress] +rps = 1 +requests_per_call = 40 +duration = "10m" + [GatewayListSoak] rps = 95 duration = "10m" @@ -20,18 +40,34 @@ duration = "10m" # Polygon Mumbai only for now receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" don_id = "fun-staging-mumbai-1" -gateway_url = "https://gateway-staging1.main.stage.cldev.sh" +gateway_url = "https://gateway-stg-one.main.stage.cldev.sh" link_token_addr = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" coordinator_addr = "0x6D6a83BB356b7242E88C1A2b290102fde26590D0" router_addr = "0x2673266D3Cd08b53494B5a92B66DEec7F1408E7A" -# comment both client and sub to automatically create a new pair + +# comment "client_addr" and "subscription_id" and test will create a new pair +# get it from logs and save client_addr = "0x89D4b58D859a536D0B888ecD5093eF5FF9e4F977" subscription_id = 47 sub_funds = 10 -#functions_call_payload = "const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); return Functions.encodeUint256(response.data.id)" -functions_call_payload = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_with_secrets = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_http = """ +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); +return Functions.encodeUint256(response.data.id); +""" +functions_call_payload_real = """ +const arg1 = args[0]; +const arg2 = args[1]; +const arg3 = args[2]; +const arg4 = args[3]; + +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/${arg1}' }); +return Functions.encodeString(JSON.stringify(secrets)); +""" secrets_slot_id = 0 secrets_version = 1693945705 -# uncomment to upload new secrets to s4 -#secrets = "{\"ltsecret\": \"1\"}" \ No newline at end of file + +# uncomment to upload new secrets to s4 and use it in your run +# TODO: not working now +#secrets = "{\"secrets\": \"secretValue\"}" \ No newline at end of file diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index c178fcc5e2..7822035208 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -21,7 +21,7 @@ func TestFunctionsLoad(t *testing.T) { MonitorLoadStats(t, ft, labels) - t.Run("functions soak test", func(t *testing.T) { + t.Run("mumbai functions soak test http", func(t *testing.T) { _, err := wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -35,8 +35,9 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, + ModeHTTPPayload, cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayload, + cfg.Common.FunctionsCallPayloadHTTP, cfg.Common.SecretsSlotID, cfg.Common.SecretsVersionID, []string{}, @@ -50,7 +51,7 @@ func TestFunctionsLoad(t *testing.T) { require.NoError(t, err) }) - t.Run("functions stress test", func(t *testing.T) { + t.Run("mumbai functions stress test http", func(t *testing.T) { _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -64,8 +65,39 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, - cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayload, + ModeHTTPPayload, + cfg.Stress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadHTTP, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions soak test only secrets", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsSoak.RPS, + cfg.SecretsSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, cfg.Common.SecretsSlotID, cfg.Common.SecretsVersionID, []string{}, @@ -78,4 +110,94 @@ func TestFunctionsLoad(t *testing.T) { Run(true) require.NoError(t, err) }) + + t.Run("mumbai functions stress test only secrets", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsStress.RPS, + cfg.SecretsStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions soak test real", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealSoak.RPS, + cfg.RealSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions stress test real", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealStress.RPS, + cfg.RealStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) } diff --git a/integration-tests/load/functions/gateway.go b/integration-tests/load/functions/gateway.go index 12406c79eb..aefe4fbedc 100644 --- a/integration-tests/load/functions/gateway.go +++ b/integration-tests/load/functions/gateway.go @@ -49,38 +49,36 @@ type RPCResponse struct { } `json:"result"` } -func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { +func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) (uint8, uint64, error) { key, err := crypto.HexToECDSA(s4Cfg.PrivateKey) if err != nil { - return err + return 0, 0, err } address := crypto.PubkeyToAddress(key.PublicKey) var payloadJSON []byte - if s4Cfg.Method == functions.MethodSecretsSet { - envelope := s4.Envelope{ - Address: address.Bytes(), - SlotID: s4Cfg.S4SetSlotID, - Version: s4Cfg.S4SetVersion, - Payload: []byte(s4Cfg.S4SetPayload), - Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, - } - signature, err := envelope.Sign(key) - if err != nil { - return err - } + envelope := s4.Envelope{ + Address: address.Bytes(), + SlotID: s4Cfg.S4SetSlotID, + Version: s4Cfg.S4SetVersion, + Payload: []byte(s4Cfg.S4SetPayload), + Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, + } + signature, err := envelope.Sign(key) + if err != nil { + return 0, 0, err + } - s4SetPayload := functions.SecretsSetRequest{ - SlotID: envelope.SlotID, - Version: envelope.Version, - Expiration: envelope.Expiration, - Payload: []byte(s4Cfg.S4SetPayload), - Signature: signature, - } + s4SetPayload := functions.SecretsSetRequest{ + SlotID: envelope.SlotID, + Version: envelope.Version, + Expiration: envelope.Expiration, + Payload: []byte(s4Cfg.S4SetPayload), + Signature: signature, + } - payloadJSON, err = json.Marshal(s4SetPayload) - if err != nil { - return err - } + payloadJSON, err = json.Marshal(s4SetPayload) + if err != nil { + return 0, 0, err } msg := &api.Message{ @@ -94,33 +92,33 @@ func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { err = msg.Sign(key) if err != nil { - return err + return 0, 0, err } codec := api.JsonRPCCodec{} rawMsg, err := codec.EncodeRequest(msg) if err != nil { - return err + return 0, 0, err } var result *RPCResponse resp, err := rc.R(). SetBody(rawMsg). Post(s4Cfg.GatewayURL) if err != nil { - return err + return 0, 0, err } if resp.StatusCode() != 200 { - return fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) + return 0, 0, fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return err + return 0, 0, err } log.Debug().Interface("Result", result).Msg("S4 secrets_set response result") for _, nodeResponse := range result.Result.Body.Payload.NodeResponses { if !nodeResponse.Body.Payload.Success { - return fmt.Errorf("node response was not succesful") + return 0, 0, fmt.Errorf("node response was not succesful") } } - return nil + return uint8(envelope.SlotID), envelope.Version, nil } func ListS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 5677e79b10..fd13922d0a 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -36,7 +36,7 @@ func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa. } } -func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -58,8 +58,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } - if err := UploadS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ + GatewayURL: m.Cfg.Common.GatewayURL, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, Method: "secrets_set", @@ -68,7 +68,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { S4SetVersion: version, S4SetExpirationPeriod: expiration, S4SetPayload: secrets, - }); err != nil { + }) + if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } return &wasp.CallResult{} @@ -80,7 +81,7 @@ func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { version := uint64(time.Now().UnixNano()) expiration := int64(60 * 60 * 1000) if err := ListS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + GatewayURL: fmt.Sprintf(m.Cfg.Common.GatewayURL), RecieverAddr: m.Cfg.Common.Receiver, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, @@ -100,7 +101,7 @@ func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.CallResult { var res *wasp.CallResult switch m.Method { case "secrets_set": - res = callSetSecrets(m) + res = callSecretsSet(m) case "secrets_list": res = callSecretsList(m) default: diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index 946afdd711..c8e63f92f2 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -1,10 +1,12 @@ package loadfunctions import ( - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "testing" + "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" - "testing" + + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" ) func TestGatewayLoad(t *testing.T) { diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index f939b2583a..d9987eaa75 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -4,22 +4,41 @@ import ( "github.com/smartcontractkit/wasp" ) -/* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ +type TestMode int + +const ( + ModeHTTPPayload TestMode = iota + ModeSecretsOnlyPayload + ModeReal +) type SingleFunctionCallGun struct { - ft *FunctionsTest - times uint32 - source string - slotID uint8 - slotVersion uint64 - args []string - subscriptionId uint64 - jobId [32]byte + ft *FunctionsTest + mode TestMode + times uint32 + source string + slotID uint8 + slotVersion uint64 + encryptedSecrets []byte + args []string + subscriptionId uint64 + jobId [32]byte } -func NewSingleFunctionCallGun(ft *FunctionsTest, times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, jobId [32]byte) *SingleFunctionCallGun { +func NewSingleFunctionCallGun( + ft *FunctionsTest, + mode TestMode, + times uint32, + source string, + slotID uint8, + slotVersion uint64, + args []string, + subscriptionId uint64, + jobId [32]byte, +) *SingleFunctionCallGun { return &SingleFunctionCallGun{ ft: ft, + mode: mode, times: times, source: source, slotID: slotID, @@ -30,8 +49,23 @@ func NewSingleFunctionCallGun(ft *FunctionsTest, times uint32, source string, sl } } -// Call implements example gun call, assertions on response bodies should be done here -func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( + m.times, + m.source, + m.slotID, + m.slotVersion, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -46,3 +80,32 @@ func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { } return &wasp.CallResult{} } + +func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequest( + m.times, + m.source, + []byte{}, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +// Call implements example gun call, assertions on response bodies should be done here +func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.CallResult { + switch m.mode { + case ModeSecretsOnlyPayload: + return m.callWithSecrets() + case ModeHTTPPayload: + return m.callWithHttp() + case ModeReal: + return m.callReal() + default: + panic("test mode must be ModeSecretsOnlyPayload, ModeHTTPPayload or ModeReal") + } +} diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 0433b5beb6..60986595b9 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -2,21 +2,22 @@ package loadfunctions import ( "crypto/ecdsa" - "fmt" + "math/big" + mrand "math/rand" + "os" + "strconv" + "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "math/big" - mrand "math/rand" - "os" - "strconv" - "time" ) type FunctionsTest struct { @@ -115,7 +116,7 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to get DON public key") } - log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded coordinator keys") + log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded DON key") tdh2pk, err := ParseTDH2Key(tpk) if err != nil { return nil, errors.Wrap(err, "failed to unmarshal tdh2 public key") @@ -126,8 +127,8 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to generate tdh2 secrets") } - if err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", cfg.Common.GatewayURL), + slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ + GatewayURL: cfg.Common.GatewayURL, PrivateKey: cfg.MumbaiPrivateKey, MessageID: strconv.Itoa(mrand.Intn(100000-1) + 1), Method: "secrets_set", @@ -136,9 +137,16 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { S4SetVersion: uint64(time.Now().UnixNano()), S4SetExpirationPeriod: 60 * 60 * 1000, S4SetPayload: encryptedSecrets, - }); err != nil { + }) + if err != nil { return nil, errors.Wrap(err, "failed to upload secrets to S4") } + cfg.Common.SecretsSlotID = slotID + cfg.Common.SecretsVersionID = slotVersion + log.Info(). + Uint8("SlotID", slotID). + Uint64("SlotVersion", slotVersion). + Msg("Set new secret") } return &FunctionsTest{ EVMClient: bc, diff --git a/integration-tests/networks/known_networks.go b/integration-tests/networks/known_networks.go deleted file mode 100644 index b98cc3abaa..0000000000 --- a/integration-tests/networks/known_networks.go +++ /dev/null @@ -1,602 +0,0 @@ -// Package networks holds all known network information for the tests -package networks - -import ( - "crypto/ecdsa" - "fmt" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink-testing-framework/utils" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" -) - -// Pre-configured test networks and their connections -// Some networks with public RPC endpoints are already filled out, but make use of environment variables to use info like -// private RPC endpoints and private keys. -var ( - // To create replica of simulated EVM network, with different chain ids - AdditionalSimulatedChainIds = []int64{3337, 4337, 5337, 6337, 7337, 8337, 9337, 9338} - AdditionalSimulatedPvtKeys = []string{ - "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", - "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", - "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", - "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", - "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", - "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", - "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", - "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", - } - // SelectedNetworks uses the SELECTED_NETWORKS env var to determine which network to run the test on. - // For use in tests that utilize multiple chains. For tests on one chain, see SelectedNetwork - // For CCIP use index 1 and 2 of SELECTED_NETWORKS to denote source and destination network respectively - SelectedNetworks []blockchain.EVMNetwork = determineSelectedNetworks() - // SelectedNetwork uses the first listed network in SELECTED_NETWORKS, for use in tests on only one chain - SelectedNetwork blockchain.EVMNetwork = SelectedNetworks[0] - - // SimulatedEVM represents a simulated network - SimulatedEVM blockchain.EVMNetwork = blockchain.SimulatedEVMNetwork - // generalEVM is a customizable network through environment variables - // This is getting little use, and causes some confusion. Can re-enable if people want it. - // generalEVM blockchain.EVMNetwork = blockchain.LoadNetworkFromEnvironment() - - // SimulatedevmNonDev1 represents a simulated network which can be used to deploy a non-dev geth node - SimulatedEVMNonDev1 = blockchain.EVMNetwork{ - Name: "source-chain", - Simulated: true, - ClientImplementation: blockchain.EthereumClientImplementation, - SupportsEIP1559: true, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://source-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://source-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - // SimulatedEVM_NON_DEV_2 represents a simulated network with chain id 2337 which can be used to deploy a non-dev geth node - SimulatedEVMNonDev2 = blockchain.EVMNetwork{ - Name: "dest-chain", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 2337, - PrivateKeys: []string{ - "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", - }, - URLs: []string{"ws://dest-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://dest-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - SimulatedEVMNonDev = blockchain.EVMNetwork{ - Name: "geth", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://geth-ethereum-geth:8546"}, - HTTPURLs: []string{"http://geth-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } - - EthereumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Ethereum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // sepoliaTestnet https://sepolia.dev/ - SepoliaTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Sepolia Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 11155111, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // goerliTestnet https://goerli.net/ - GoerliTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Goerli Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 5, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - KlaytnMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 8217, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // klaytnBaobab https://klaytn.foundation/ - KlaytnBaobab blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Baobab", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 1001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - MetisAndromeda blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Andromeda", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 1088, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // metisStardust https://www.metis.io/ - MetisStardust blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Stardust", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 588, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ArbitrumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 42161, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - // arbitrumGoerli https://developer.offchainlabs.com/docs/public_chains - ArbitrumGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 421613, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - OptimismMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 10, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // optimismGoerli https://dev.optimism.io/kovan-to-goerli/ - OptimismGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 420, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - RSKMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 30, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - // rskTestnet https://www.rsk.co/ - RSKTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Testnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 31, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - PolygonMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 137, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 550, - DefaultGasLimit: 6000000, - } - - // PolygonMumbai https://mumbai.polygonscan.com/ - PolygonMumbai blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mumbai", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 80001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 100000, - FinalityDepth: 550, - DefaultGasLimit: 8000000, - } - - AvalancheMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Avalanche Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43114, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - AvalancheFuji = blockchain.EVMNetwork{ - Name: "Avalanche Fuji", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43113, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - Quorum = blockchain.EVMNetwork{ - Name: "Quorum", - SupportsEIP1559: false, - ClientImplementation: blockchain.QuorumClientImplementation, - ChainID: 1337, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - BaseGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 84531, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - } - - CeloAlfajores = blockchain.EVMNetwork{ - Name: "Celo Alfajores", - SupportsEIP1559: false, - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 44787, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ScrollSepolia = blockchain.EVMNetwork{ - Name: "Scroll Sepolia", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534351, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - ScrollMainnet = blockchain.EVMNetwork{ - Name: "Scroll Mainnet", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534352, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - CeloMainnet = blockchain.EVMNetwork{ - Name: "Celo", - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 42220, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - BaseMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 8453, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - } - - BSCTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 97, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - FinalityTag: true, - } - - BSCMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 56, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - FinalityTag: true, - } - - MappedNetworks = map[string]blockchain.EVMNetwork{ - "SIMULATED": SimulatedEVM, - "SIMULATED_1": SimulatedEVMNonDev1, - "SIMULATED_2": SimulatedEVMNonDev2, - "SIMULATED_NONDEV": SimulatedEVMNonDev, - // "GENERAL": generalEVM, // See above - "ETHEREUM_MAINNET": EthereumMainnet, - "GOERLI": GoerliTestnet, - "SEPOLIA": SepoliaTestnet, - "KLAYTN_MAINNET": KlaytnMainnet, - "KLAYTN_BAOBAB": KlaytnBaobab, - "METIS_ANDROMEDA": MetisAndromeda, - "METIS_STARDUST": MetisStardust, - "ARBITRUM_MAINNET": ArbitrumMainnet, - "ARBITRUM_GOERLI": ArbitrumGoerli, - "OPTIMISM_MAINNET": OptimismMainnet, - "OPTIMISM_GOERLI": OptimismGoerli, - "BASE_GOERLI": BaseGoerli, - "CELO_ALFAJORES": CeloAlfajores, - "CELO_MAINNET": CeloMainnet, - "RSK": RSKTestnet, - "MUMBAI": PolygonMumbai, - "POLYGON_MAINNET": PolygonMainnet, - "AVALANCHE_FUJI": AvalancheFuji, - "AVALANCHE_MAINNET": AvalancheMainnet, - "QUORUM": Quorum, - "SCROLL_SEPOLIA": ScrollSepolia, - "SCROLL_MAINNET": ScrollMainnet, - "BASE_MAINNET": BaseMainnet, - "BSC_TESTNET": BSCTestnet, - "BSC_MAINNET": BSCMainnet, - } -) - -// determineSelectedNetworks uses `SELECTED_NETWORKS` to determine which networks to run the tests on. -// Use DetermineSelectedNetwork for tests that only use one network -func determineSelectedNetworks() []blockchain.EVMNetwork { - logging.Init() - selectedNetworks := make([]blockchain.EVMNetwork, 0) - rawSelectedNetworks := strings.ToUpper(os.Getenv("SELECTED_NETWORKS")) - setNetworkNames := strings.Split(rawSelectedNetworks, ",") - - for _, setNetworkName := range setNetworkNames { - if chosenNetwork, valid := MappedNetworks[setNetworkName]; valid { - log.Info(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Network Name", chosenNetwork.Name). - Msg("Read network choice from 'SELECTED_NETWORKS'") - setURLs(setNetworkName, &chosenNetwork) - setKeys(setNetworkName, &chosenNetwork) - selectedNetworks = append(selectedNetworks, chosenNetwork) - } else { - validNetworks := make([]string, 0) - for validNetwork := range MappedNetworks { - validNetworks = append(validNetworks, validNetwork) - } - log.Fatal(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Valid Networks", strings.Join(validNetworks, ", ")). - Msg("SELECTED_NETWORKS value is invalid. Use a valid network(s).") - } - } - return selectedNetworks -} - -// setURLs sets a network URL(s) based on env vars -func setURLs(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - wsEnvVar := fmt.Sprintf("%s_URLS", prefix) - httpEnvVar := fmt.Sprintf("%s_HTTP_URLS", prefix) - wsEnvURLs, err := utils.GetEnv(wsEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", wsEnvVar).Msg("Error getting env var") - } - httpEnvURLs, err := utils.GetEnv(httpEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", httpEnvVar).Msg("Error getting env var") - } - if wsEnvURLs == "" { - evmUrls, err := utils.GetEnv("EVM_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_URLS").Msg("Error getting env var") - } - evmhttpUrls, err := utils.GetEnv("EVM_HTTP_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_HTTP_URLS").Msg("Error getting env var") - } - wsURLs := strings.Split(evmUrls, ",") - httpURLs := strings.Split(evmhttpUrls, ",") - log.Warn().Msgf("No '%s' env var defined, defaulting to 'EVM_URLS'", wsEnvVar) - network.URLs = wsURLs - network.HTTPURLs = httpURLs - return - } - - wsURLs := strings.Split(wsEnvURLs, ",") - httpURLs := strings.Split(httpEnvURLs, ",") - network.URLs = wsURLs - network.HTTPURLs = httpURLs - log.Info().Msg("Read network URLs") -} - -// setKeys sets a network's private key(s) based on env vars -func setKeys(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - envVar := fmt.Sprintf("%s_KEYS", prefix) - keysFromEnv, err := utils.GetEnv(envVar) - if err != nil { - log.Fatal().Err(err).Str("env var", envVar).Msg("Error getting env var") - } - if keysFromEnv == "" { - log.Warn().Msg(fmt.Sprintf("No '%s' env var defined, defaulting to 'EVM_KEYS'", envVar)) - keysFromEnv = os.Getenv("EVM_KEYS") - } - keys := strings.Split(keysFromEnv, ",") - for i, key := range keys { - keys[i] = strings.TrimPrefix(key, "0x") - } - network.PrivateKeys = keys - - // log public keys for debugging - publicKeys := []string{} - for _, key := range network.PrivateKeys { - publicKey, err := privateKeyToAddress(key) - if err != nil { - log.Fatal().Err(err).Msg("Error getting public key from private key") - } - publicKeys = append(publicKeys, publicKey) - } - log.Info().Interface("Funding Addresses", publicKeys).Msg("Read network Keys") -} - -func privateKeyToAddress(privateKeyString string) (string, error) { - privateKey, err := crypto.HexToECDSA(privateKeyString) - if err != nil { - return "", err - } - publicKey := privateKey.Public() - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - return "", fmt.Errorf("error casting private key to public ECDSA key") - } - return crypto.PubkeyToAddress(*publicKeyECDSA).Hex(), nil -} diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 933014a169..c66a180356 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -22,9 +22,10 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 47a16de109..dca84ab09c 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -20,10 +20,11 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" "github.com/google/uuid" diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index ecacce90ca..bc914c329b 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -21,10 +21,11 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 346f0897d4..384729dfab 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 25791161bc..d056d58e30 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -18,10 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index 2074eecaf7..59eb5e3980 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -18,10 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 4a75d92d5d..f3d3ed9369 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -19,11 +19,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index d6ac5ce1cf..c944b7a753 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -1,6 +1,7 @@ package reorg import ( + "context" "fmt" "math/big" "os" @@ -23,13 +24,13 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" - "context" "github.com/onsi/gomega" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) const ( diff --git a/integration-tests/runner_helpers.go b/integration-tests/runner_helpers.go index 1795006457..43268a703a 100644 --- a/integration-tests/runner_helpers.go +++ b/integration-tests/runner_helpers.go @@ -12,12 +12,12 @@ import ( "strings" "time" - gh "github.com/cli/go-gh/v2" + "github.com/cli/go-gh/v2" "github.com/ethereum/go-ethereum/crypto" "github.com/manifoldco/promptui" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/networks" + "github.com/smartcontractkit/chainlink-testing-framework/networks" ) func waitForWorkflowRun(branch, ghUser string) (string, error) { diff --git a/integration-tests/scripts/buildTestMatrixList.sh b/integration-tests/scripts/buildTestMatrixList.sh new file mode 100755 index 0000000000..25f7271509 --- /dev/null +++ b/integration-tests/scripts/buildTestMatrixList.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +# requires a path to a test file to compare the test list against +# requires a matrix job name to be passed in, for example "automation" +# requires a node label to be passed in, for example "ubuntu-latest" + +set -e + +# get this scripts directory +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +cd "$SCRIPT_DIR"/../ || exit 1 + +FILENAME=$1 +MATRIX_JOB_NAME=$2 +NODE_LABEL=$3 + +# Get list of test names from JSON file +JSONFILE="${FILENAME}_test_list.json" +COUNTER=1 + +# Build a JSON object in the format expected by our integration-tests workflow matrix +matrix_output() { + local counter=$1 + local job_name=$2 + local test_name=$3 + local node_label=$4 + local counter_out=$(printf "%02d\n" $counter) + echo -n "{\"name\": \"${job_name}-${counter_out}\", \"file\": \"${job_name}\",\"nodes\": 1, \"os\": \"${node_label}\", \"pyroscope_env\": \"ci-smoke-${job_name}-evm-simulated\", \"run\": \"-run '^${test_name}$'\"}" +} + +# Read the JSON file and loop through 'tests' and 'run' +jq -c '.tests[]' ${JSONFILE} | while read -r test; do + testName=$(echo ${test} | jq -r '.name') + subTests=$(echo ${test} | jq -r '.run[]?.name // empty') + output="" + + # Loop through subtests, if any, and print in the desired format + if [ -n "$subTests" ]; then + for subTest in $subTests; do + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${NODE_LABEL} + ((COUNTER++)) + done + else + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${NODE_LABEL} + ((COUNTER++)) + fi + +done > "./tmpout.json" +OUTPUT=$(cat ./tmpout.json) +echo "[${OUTPUT}]" +rm ./tmpout.json diff --git a/integration-tests/scripts/buildTests b/integration-tests/scripts/buildTests index 0ec0533694..c487521519 100755 --- a/integration-tests/scripts/buildTests +++ b/integration-tests/scripts/buildTests @@ -26,5 +26,3 @@ do go test -c ./"${x}" done IFS=$OIFS - - diff --git a/integration-tests/scripts/compareTestList.sh b/integration-tests/scripts/compareTestList.sh new file mode 100755 index 0000000000..8cc916c7d6 --- /dev/null +++ b/integration-tests/scripts/compareTestList.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# accepts a path to a test file to compare the test list against + +set -e + +# get this scripts directory +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +cd "$SCRIPT_DIR"/../ || exit 1 + +FILENAME=$1 + +TESTLIST=$(cat ${FILENAME} | grep "func Test.*\(t \*testing.T\)" | grep -o 'Test[A-Za-z0-9_]*') + +# convert the test list from above into json in the form {"tests":[{"name":"TestName"}]} +TESTLISTJSON=$(echo $TESTLIST | jq -R -s -c '{tests: split(" ") | map({"name":.})}') + +# Get list of test names from JSON file +JSONFILE="${FILENAME}_test_list.json" +JSONTESTLIST=$(jq -r '.tests[].name' ${JSONFILE}) + +# Convert lists to arrays +TESTLIST_ARRAY=($(echo "$TESTLIST")) +JSONTESTLIST_ARRAY=($(echo "$JSONTESTLIST")) + +ERRORS_FOUND=false + +# Compare TESTLIST_ARRAY against JSONTESTLIST_ARRAY +for test in "${TESTLIST_ARRAY[@]}"; do + if [[ ! " ${JSONTESTLIST_ARRAY[@]} " =~ " ${test} " ]]; then + echo "$test exists only in ${FILENAME}." + ERRORS_FOUND=true + fi +done + +# Compare JSONTESTLIST_ARRAY against TESTLIST_ARRAY +for test in "${JSONTESTLIST_ARRAY[@]}"; do + if [[ ! " ${TESTLIST_ARRAY[@]} " =~ " ${test} " ]]; then + echo "$test exists only in ${JSONFILE}." + ERRORS_FOUND=true + fi +done + +if [ "$ERRORS_FOUND" = true ] ; then + echo "Test lists do not match. Please update ${JSONFILE} with the updated tests to run in CI." + exit 1 +fi diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 57ca733b59..67b9b0b264 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -6,29 +6,34 @@ import ( "math/big" "os" "strconv" - "strings" "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" - "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-env/logging" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) +var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) + const ( automationDefaultUpkeepGasLimit = uint32(2500000) automationDefaultLinkFunds = int64(9e18) @@ -38,25 +43,6 @@ const ( ) var ( - automationBaseTOML = `[Feature] -LogPoller = true - -[OCR2] -Enabled = true - -[Keeper] -TurnLookBack = 0 - -[Keeper.Registry] -SyncInterval = '5m' -PerformGasOverhead = 150_000 - -[P2P] -[P2P.V2] -Enabled = true -AnnounceAddresses = ["0.0.0.0:6690"] -ListenAddresses = ["0.0.0.0:6690"]` - defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(200000000), FlatFeeMicroLINK: uint32(0), @@ -128,12 +114,9 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { require.NoError(t, err, "Error getting upgrade version") testName = "node-upgrade" } - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, testEnv := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( t, testName, registryVersion, defaultOCRRegistryConfig, nodeUpgrade, ) - if onlyStartRunner { - return - } // Use the name to determine if this is a log trigger or not isLogTrigger := name == "registry_2_1_logtrigger" @@ -181,7 +164,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - actions.UpgradeChainlinkNodeVersions(testEnv, upgradeImage, upgradeVersion, chainlinkNodes[i]) + actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.CLNodes[i]) time.Sleep(time.Second * 10) expect = expect + 5 gom.Eventually(func(g gomega.Gomega) { @@ -230,6 +213,172 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { } } +func TestSetUpkeepTriggerConfig(t *testing.T) { + t.Parallel() + l := utils.GetTestLogger(t) + + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( + t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, + ) + + consumers, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + ) + + // Start log trigger based upkeeps for all consumers + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Waiting for all upkeeps to perform") + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 5 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + + topic0InBytesMatch := [32]byte{ + 61, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d + + topic0InBytesNoMatch := [32]byte{ + 62, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } // changed the first byte from 61 to 62 to make it not match + + bytes0 := [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 + + // Update the trigger config so no upkeeps are triggered + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesNoMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err := chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) + + // Wait for 10 seconds to let in-flight upkeeps finish + time.Sleep(10 * time.Second) + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetNoMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetNoMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + l.Info().Msg("Making sure the counter stays consistent") + gom.Consistently(func(g gomega.Gomega) { + for i := 0; i < len(upkeepIDs); i++ { + // Expect the counter to remain constant (At most increase by 2 to account for stale performs) because the upkeep trigger config is not met + bufferCount := int64(2) + latestCounter, err := consumers[i].Counter(context.Background()) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) + g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSetNoMatch[i].Int64()+bufferCount), + "Expected consumer counter to remain less than or equal to %d, but got %d", + countersAfterSetNoMatch[i].Int64()+bufferCount, latestCounter.Int64()) + } + }, "1m", "1s").Should(gomega.Succeed()) + + // Update the trigger config, so upkeeps start performing again + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetMatch = make([]*big.Int, len(upkeepIDs)) + + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + // Wait for 30 seconds to make sure backend is ready + time.Sleep(30 * time.Second) + // Start the consumers again + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Making sure the counter starts increasing again") + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := int64(5) + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", countersAfterSetMatch[i].Int64()+expect), + "Expected consumer counter to be greater than %d, but got %d", countersAfterSetMatch[i].Int64()+expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer +} + func TestAutomationAddFunds(t *testing.T) { t.Parallel() registryVersions := map[string]ethereum.KeeperRegistryVersion{ @@ -242,13 +391,9 @@ func TestAutomationAddFunds(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "add-funds", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false) @@ -298,13 +443,9 @@ func TestAutomationPauseUnPause(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) @@ -386,13 +527,9 @@ func TestAutomationRegisterUpkeep(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) @@ -462,12 +599,9 @@ func TestAutomationPauseRegistry(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "pause-registry", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) gom := gomega.NewGomegaWithT(t) @@ -524,13 +658,9 @@ func TestAutomationKeeperNodesDown(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) gom := gomega.NewGomegaWithT(t) @@ -614,13 +744,9 @@ func TestAutomationPerformSimulation(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "perform-simulation", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumersPerformance, _ := actions.DeployPerformanceConsumers( t, @@ -683,13 +809,9 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( t, @@ -767,7 +889,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { highCheckGasLimit := automationDefaultRegistryConfig highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) require.NoError(t, err, "Error building OCR config") err = registry.SetConfig(highCheckGasLimit, ocrConfig) @@ -801,13 +923,9 @@ func TestUpdateCheckData(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( t, @@ -865,103 +983,78 @@ func TestUpdateCheckData(t *testing.T) { } } -func setupAutomationTest( +func setupAutomationTestDocker( t *testing.T, testName string, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, statefulDb bool, ) ( - chainClient blockchain.EVMClient, - chainlinkNodes []*client.ChainlinkK8sClient, - contractDeployer contracts.ContractDeployer, - linkToken contracts.LinkToken, - registry contracts.KeeperRegistry, - registrar contracts.KeeperRegistrar, - onlyStartRunner bool, - testEnvironment *environment.Environment, + blockchain.EVMClient, + []*client.ChainlinkClient, + contracts.ContractDeployer, + contracts.LinkToken, + contracts.KeeperRegistry, + contracts.KeeperRegistrar, + *test_env.CLClusterTestEnv, ) { // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.SelectedNetwork - evmConfig := eth.New(nil) - if !network.Simulated { - evmConfig = eth.New(ð.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - chainlinkProps := map[string]any{ - "toml": client.AddNetworksConfig(automationBaseTOML, network), - "secretsToml": client.AddSecretTomlConfig("https://google.com", "username1", "password1"), - "db": map[string]any{ - "stateful": statefulDb, - }, - } - - cd, err := chainlink.NewDeployment(5, chainlinkProps) - require.NoError(t, err, "Failed to create chainlink deployment") - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-automation-%s-%s", testName, strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, - }). - AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() - - require.NoError(t, err, "Error setting up test environment") - - onlyStartRunner = testEnvironment.WillUseRemoteRunner() - if !onlyStartRunner { - chainClient, err = blockchain.NewEVMClient(network, testEnvironment) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err = contracts.NewContractDeployer(chainClient) - require.NoError(t, err, "Error building contract deployer") - chainlinkNodes, err = client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - t.Cleanup(func() { - if err := actions.ReturnFunds(chainlinkNodes, chainClient); err != nil { - log.Error().Err(err).Msg("Error returning funds") - } - }) - chainClient.ParallelTransactions(true) - - txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) - require.NoError(t, err, "Error estimating cost for Chainlink Operations") - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) - require.NoError(t, err, "Error funding Chainlink nodes") - - linkToken, err = contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying LINK token") - - registry, registrar = actions.DeployAutoOCRRegistryAndRegistrar( - t, - registryVersion, - registryConfig, - linkToken, - contractDeployer, - chainClient, - ) - - // Fund the registry with LINK - err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - - actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, registryVersion) - nodesWithoutBootstrap := chainlinkNodes[1:] - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, registryConfig, registrar.Address(), 30*time.Second) - require.NoError(t, err, "Error building OCR config vars") - err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) - require.NoError(t, err, "Registry config should be set successfully") - require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") - // Register cleanup for any test - t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") - }) - } - return chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, testEnvironment + // build the node config + clNodeConfig := node.NewConfig(node.BaseConf) + syncInterval := models.MustMakeDuration(5 * time.Minute) + clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) + clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval + clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) + clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} + clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} + + // launch the environment + env, err := test_env.NewCLTestEnvBuilder(). + WithGeth(). + WithMockServer(1). + WithCLNodes(5). + WithCLNodeConfig(clNodeConfig). + WithFunding(big.NewFloat(.5)). + Build() + require.NoError(t, err, "Error deploying test environment") + env.ParallelTransactions(true) + + txCost, err := env.EVMClient.EstimateCostForChainlinkOperations(1000) + require.NoError(t, err, "Error estimating cost for Chainlink Operations") + nodeClients := env.GetAPIs() + workerNodes := nodeClients[1:] + err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, txCost) + require.NoError(t, err, "Error funding Chainlink nodes") + + linkToken, err := env.ContractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Error deploying LINK token") + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, + registryVersion, + registryConfig, + linkToken, + env.ContractDeployer, + env.EVMClient, + ) + + // Fund the registry with LINK + err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) + require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + + err = actions.CreateOCRKeeperJobsLocal(nodeClients, registry.Address(), network.ChainID, 0, registryVersion) + require.NoError(t, err, "Error creating OCR Keeper Jobs") + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, workerNodes, registryConfig, registrar.Address(), 30*time.Second) + require.NoError(t, err, "Error building OCR config vars") + err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) + require.NoError(t, err, "Registry config should be set successfully") + require.NoError(t, env.EVMClient.WaitForEvents(), "Waiting for config to be set") + + return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env } diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json new file mode 100644 index 0000000000..515e163270 --- /dev/null +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -0,0 +1,109 @@ +{ + "tests": [ + { + "name": "TestAutomationBasic", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1_conditional" + }, + { + "name": "registry_2_1_logtrigger" + } + ] + }, + { + "name": "TestAutomationAddFunds", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPauseUnPause", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationRegisterUpkeep", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPauseRegistry", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationKeeperNodesDown", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPerformSimulation", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationCheckPerformGasLimit", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestUpdateCheckData", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestSetUpkeepTriggerConfig" + } + ] +} diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json new file mode 100644 index 0000000000..864dbfdb1c --- /dev/null +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -0,0 +1,70 @@ +{ + "tests": [ + { + "name": "TestKeeperBasicSmoke" + }, + { + "name": "TestKeeperBlockCountPerTurn", + "run": [ + { + "name": "registry_1_1" + }, + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperSimulation" + }, + { + "name": "TestKeeperCheckPerformGasLimit", + "run": [ + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperRegisterUpkeep" + }, + { + "name": "TestKeeperAddFunds" + }, + { + "name": "TestKeeperRemove" + }, + { + "name": "TestKeeperPauseRegistry" + }, + { + "name": "TestKeeperMigrateRegistry" + }, + { + "name": "TestKeeperNodeDown", + "run": [ + { + "name": "registry_1_1" + }, + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperPauseUnPauseUpkeep" + }, + { + "name": "TestKeeperUpdateCheckData" + } + ] +} diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 6588586c39..adaaf21ba1 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -16,13 +16,14 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 504750fdaf..50a21b81d8 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -15,13 +15,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) func TestOCR2VRFRedeemModel(t *testing.T) { diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 1c210af117..07aa3b2c4e 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -36,11 +36,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" )