From ccd45ab57da474e53e9c11e317210966870f1de6 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Tue, 14 May 2024 15:39:30 +0200 Subject: [PATCH 01/17] update all workflows to use GAP's Grafana URL and API token required for URL shortening (#13044) --- .../action.yml | 4 + .../setup-create-base64-config/action.yml | 4 + .../action.yml | 4 + .../setup-merge-base64-config/action.yml | 5 + .../workflows/automation-nightly-tests.yml | 17 +- .../workflows/automation-ondemand-tests.yml | 18 +- .../workflows/client-compatibility-tests.yml | 11 ++ .../evm-version-compatibility-tests.yml | 17 +- .github/workflows/integration-tests.yml | 51 ++++- .github/workflows/live-testnet-tests.yml | 187 ++++++++++++++++-- .github/workflows/live-vrf-tests.yml | 17 +- .../on-demand-vrfv2-performance-test.yml | 3 + .../on-demand-vrfv2plus-performance-test.yml | 3 + 13 files changed, 323 insertions(+), 18 deletions(-) diff --git a/.github/actions/setup-create-base64-config-live-testnets/action.yml b/.github/actions/setup-create-base64-config-live-testnets/action.yml index 879dcce6df3..0dac6e9d55b 100644 --- a/.github/actions/setup-create-base64-config-live-testnets/action.yml +++ b/.github/actions/setup-create-base64-config-live-testnets/action.yml @@ -33,6 +33,8 @@ inputs: description: Grafana URL grafanaDashboardUrl: description: Grafana dashboard URL + grafanaBearerToken: + description: Grafana bearer token network: description: Network to run tests on httpEndpoints: @@ -62,6 +64,7 @@ runs: LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} GRAFANA_URL: ${{ inputs.grafanaUrl }} GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + GRAFANA_BEARER_TOKEN: ${{ inputs.grafanaBearerToken }} NETWORK: ${{ inputs.network }} HTTP_ENDPOINTS: ${{ inputs.httpEndpoints }} WS_ENDPOINTS: ${{ inputs.wsEndpoints }} @@ -115,6 +118,7 @@ runs: [Logging.Grafana] base_url="$GRAFANA_URL" dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" [Network] selected_networks=["$NETWORK"] diff --git a/.github/actions/setup-create-base64-config/action.yml b/.github/actions/setup-create-base64-config/action.yml index 447f5be42cb..46de20b6cd6 100644 --- a/.github/actions/setup-create-base64-config/action.yml +++ b/.github/actions/setup-create-base64-config/action.yml @@ -35,6 +35,8 @@ inputs: description: Grafana URL grafanaDashboardUrl: description: Grafana dashboard URL + grafanaBearerToken: + description: Grafana bearer token ethExecutionClient: description: Ethereum execution client to use (geth, besu, nethermind or erigon) customEthClientDockerImage: @@ -62,6 +64,7 @@ runs: LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} GRAFANA_URL: ${{ inputs.grafanaUrl }} GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + GRAFANA_BEARER_TOKEN: ${{ inputs.grafanaBearerToken }} ETH_EXECUTION_CLIENT: ${{ inputs.ethExecutionClient }} CUSTOM_ETH_CLIENT_DOCKER_IMAGE: ${{ inputs.customEthClientDockerImage }} run: | @@ -139,6 +142,7 @@ runs: [Logging.Grafana] base_url="$GRAFANA_URL" dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" [PrivateEthereumNetwork] execution_layer="$execution_layer" diff --git a/.github/actions/setup-create-base64-upgrade-config/action.yml b/.github/actions/setup-create-base64-upgrade-config/action.yml index 8f514784725..a7cfcafde4c 100644 --- a/.github/actions/setup-create-base64-upgrade-config/action.yml +++ b/.github/actions/setup-create-base64-upgrade-config/action.yml @@ -34,6 +34,8 @@ inputs: description: Grafana URL grafanaDashboardUrl: description: Grafana dashboard URL + grafanaBearerToken: + description: Grafana bearer token runs: using: composite @@ -56,6 +58,7 @@ runs: LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} GRAFANA_URL: ${{ inputs.grafanaUrl }} GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + GRAFANA_BEARER_TOKEN: ${{ inputs.grafanaBearerToken }} run: | function convert_to_toml_array() { local IFS=',' @@ -109,6 +112,7 @@ runs: [Logging.Grafana] base_url="$GRAFANA_URL" dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" EOF BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) diff --git a/.github/actions/setup-merge-base64-config/action.yml b/.github/actions/setup-merge-base64-config/action.yml index 43dcab940ab..48ca96bf948 100644 --- a/.github/actions/setup-merge-base64-config/action.yml +++ b/.github/actions/setup-merge-base64-config/action.yml @@ -53,6 +53,11 @@ runs: basic_auth_secret="$LOKI_BASIC_AUTH" # legacy, you only need this to access the cloud version # bearer_token_secret="bearer_token" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" EOF echo "$decoded_toml" >> final_config.toml diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml index b44a7f56e65..0aeaf1ae47a 100644 --- a/.github/workflows/automation-nightly-tests.yml +++ b/.github/workflows/automation-nightly-tests.yml @@ -87,6 +87,20 @@ jobs: uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.head_ref || github.ref_name }} + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-upgrade-config with: @@ -101,8 +115,9 @@ jobs: lokiTenantId: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} lokiBasicAuth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@5dd916d08c03cb5f9a97304f4f174820421bb946 # v2.3.11 env: diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index dade0f331b9..c232a6ba9e6 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -217,6 +217,20 @@ jobs: echo "image=$READ_CL_UPGR_IMAGE" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML config env: SELECTED_NETWORKS: ${{ matrix.tests.network }} @@ -233,8 +247,9 @@ jobs: LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} LOGSTREAM_LOG_TARGETS: ${{ vars.LOGSTREAM_LOG_TARGETS }} - GRAFANA_URL: ${{ vars.GRAFANA_URL }} + GRAFANA_URL: "http://localhost:8080/primary" GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + $GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} run: | echo ::add-mask::$UPGRADE_IMAGE echo ::add-mask::$OLD_IMAGE @@ -285,6 +300,7 @@ jobs: [Logging.Grafana] base_url="$GRAFANA_URL" dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" [Pyroscope] enabled=$pyroscope_enabled diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 0ca81c422fe..6b327824fb6 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -164,6 +164,9 @@ jobs: PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} ETH2_EL_CLIENT: ${{matrix.client}} CHAINLINK_VERSION: ${{ github.sha }} + GRAFANA_URL: "http://localhost:8080/primary" + GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} run: | convert_to_toml_array() { local IFS=',' @@ -205,6 +208,11 @@ jobs: server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" key_secret="$PYROSCOPE_KEY" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dashboard_url="$GRAFANA_DASHBOARD_URL" + bearer_token_secret="$GRAFANA_BEARER_TOKEN" [PrivateEthereumNetwork] ethereum_version="eth2" @@ -242,6 +250,9 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@5dd916d08c03cb5f9a97304f4f174820421bb946 # v2.3.11 start-slack-thread: name: Start Slack Thread diff --git a/.github/workflows/evm-version-compatibility-tests.yml b/.github/workflows/evm-version-compatibility-tests.yml index 8d8240b474b..db13b241053 100644 --- a/.github/workflows/evm-version-compatibility-tests.yml +++ b/.github/workflows/evm-version-compatibility-tests.yml @@ -209,6 +209,20 @@ jobs: else echo "run_command=./smoke/${{ matrix.evm_node.product }}_test.go" >> "$GITHUB_OUTPUT" fi + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config with: @@ -221,8 +235,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} ethExecutionClient: ${{ matrix.evm_node.eth_client }} customEthClientDockerImage: ${{ matrix.evm_node.docker_image }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 992a7ad1f50..6d365b6d801 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -317,6 +317,20 @@ jobs: else echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" fi + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config with: @@ -332,8 +346,9 @@ jobs: lokiTenantId: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} lokiBasicAuth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" # This is GAP's address grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} ## Run this step when changes that require tests to be run are made - name: Run Tests @@ -420,6 +435,20 @@ jobs: else echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" fi + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config with: @@ -435,8 +464,9 @@ jobs: lokiTenantId: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} lokiBasicAuth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" # This is GAP's address grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' @@ -631,6 +661,20 @@ jobs: if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | docker logs otel-collector + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config with: @@ -646,8 +690,9 @@ jobs: lokiTenantId: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} lokiBasicAuth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 0f081bedaf1..470dd8aa1cd 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -247,6 +247,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -261,8 +275,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "sepolia" httpEndpoints: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_SEPOLIA_URLS }} @@ -320,6 +335,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -334,8 +363,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "bsc_testnet" httpEndpoints: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_BSC_TESTNET_URLS }} @@ -393,6 +423,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -407,8 +451,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "optimism_sepolia" httpEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} @@ -466,6 +511,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -480,8 +539,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "arbitrum_sepolia" httpEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} @@ -535,6 +595,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -549,8 +623,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "base_sepolia" httpEndpoints: ${{ secrets.QA_BASE_SEPOLIA_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_BASE_SEPOLIA_URLS }} @@ -608,6 +683,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -622,8 +711,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "polygon_mumbai" httpEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} @@ -681,6 +771,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -695,8 +799,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "avalanche_fuji" httpEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} @@ -754,6 +859,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -768,8 +887,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "fantom_testnet" httpEndpoints: ${{ secrets.QA_FANTOM_TESTNET_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_FANTOM_TESTNET_URLS }} @@ -823,6 +943,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -837,8 +971,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "celo_alfajores" httpEndpoints: ${{ secrets.QA_CELO_ALFAJORES_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_CELO_ALFAJORES_URLS }} @@ -892,6 +1027,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -906,8 +1055,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "scroll_sepolia" httpEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} @@ -961,6 +1111,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -975,8 +1139,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: "linea_goerli" httpEndpoints: ${{ secrets.QA_LINEA_GOERLI_HTTP_URLS }} wsEndpoints: ${{ secrets.QA_LINEA_GOERLI_URLS }} diff --git a/.github/workflows/live-vrf-tests.yml b/.github/workflows/live-vrf-tests.yml index 9b52af70ff0..a4242926008 100644 --- a/.github/workflows/live-vrf-tests.yml +++ b/.github/workflows/live-vrf-tests.yml @@ -138,6 +138,20 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 + - name: Setup GAP for Grafana + uses: smartcontractkit/.github/actions/setup-gap@main + with: + # aws inputs + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + # other inputs + duplicate-authorization-header: "true" + # metrics inputs + metrics-job-name: "grafana" + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config-live-testnets with: @@ -149,8 +163,9 @@ jobs: lokiTenantId: ${{ vars.LOKI_TENANT_ID }} lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} - grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} network: ${{ matrix.network }} httpEndpoints: ${{ secrets[env.HTTP_URLS_SECRET_NAME] }} wsEndpoints: ${{ secrets[env.URLS_SECRET_NAME] }} diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index f520e2307d9..9695da8d6da 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -38,6 +38,9 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + GRAFANA_URL: "http://localhost:8080/primary" + GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} WASP_LOG_LEVEL: info steps: - name: Collect Metrics diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 16d37617a68..1d3e6a06148 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -38,6 +38,9 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + GRAFANA_URL: "http://localhost:8080/primary" + GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} WASP_LOG_LEVEL: info steps: - name: Collect Metrics From 1451b2b6321f997c2df2c0b7fd05d6ba1eac30e4 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 14 May 2024 10:51:16 -0400 Subject: [PATCH 02/17] Reduce number of inserts for multi-server (#13189) --- .changeset/twelve-wolves-clean.md | 5 ++ core/services/relay/evm/mercury/orm.go | 36 ++++++-- core/services/relay/evm/mercury/orm_test.go | 87 ++++++++++++++----- .../relay/evm/mercury/persistence_manager.go | 2 +- .../services/relay/evm/mercury/transmitter.go | 11 ++- 5 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 .changeset/twelve-wolves-clean.md diff --git a/.changeset/twelve-wolves-clean.md b/.changeset/twelve-wolves-clean.md new file mode 100644 index 00000000000..c38fbe3fd83 --- /dev/null +++ b/.changeset/twelve-wolves-clean.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Performance improvements for mercury single insert for multiple mercury servers #internal diff --git a/core/services/relay/evm/mercury/orm.go b/core/services/relay/evm/mercury/orm.go index 6426ef54a5d..65df9ab4cc6 100644 --- a/core/services/relay/evm/mercury/orm.go +++ b/core/services/relay/evm/mercury/orm.go @@ -5,6 +5,8 @@ import ( "crypto/sha256" "database/sql" "errors" + "fmt" + "strings" "sync" "github.com/ethereum/go-ethereum/common" @@ -19,7 +21,7 @@ import ( ) type ORM interface { - InsertTransmitRequest(ctx context.Context, serverURL string, req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext) error + InsertTransmitRequest(ctx context.Context, serverURLs []string, req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext) error DeleteTransmitRequests(ctx context.Context, serverURL string, reqs []*pb.TransmitRequest) error GetTransmitRequests(ctx context.Context, serverURL string, jobID int32) ([]*Transmission, error) PruneTransmitRequests(ctx context.Context, serverURL string, jobID int32, maxSize int) error @@ -42,11 +44,14 @@ func NewORM(ds sqlutil.DataSource) ORM { } // InsertTransmitRequest inserts one transmit request if the payload does not exist already. -func (o *orm) InsertTransmitRequest(ctx context.Context, serverURL string, req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext) error { +func (o *orm) InsertTransmitRequest(ctx context.Context, serverURLs []string, req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext) error { feedID, err := FeedIDFromReport(req.Payload) if err != nil { return err } + if len(serverURLs) == 0 { + return errors.New("no server URLs provided") + } var wg sync.WaitGroup wg.Add(2) @@ -54,11 +59,30 @@ func (o *orm) InsertTransmitRequest(ctx context.Context, serverURL string, req * go func() { defer wg.Done() - _, err1 = o.ds.ExecContext(ctx, ` - INSERT INTO mercury_transmit_requests (server_url, payload, payload_hash, config_digest, epoch, round, extra_hash, job_id, feed_id) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + + values := make([]string, len(serverURLs)) + args := []interface{}{ + req.Payload, + hashPayload(req.Payload), + reportCtx.ConfigDigest[:], + reportCtx.Epoch, + reportCtx.Round, + reportCtx.ExtraHash[:], + jobID, + feedID[:], + } + for i, serverURL := range serverURLs { + // server url is the only thing that changes, might as well re-use + // the same parameters for each insert + values[i] = fmt.Sprintf("($1, $2, $3, $4, $5, $6, $7, $8, $%d)", i+9) + args = append(args, serverURL) + } + + _, err1 = o.ds.ExecContext(ctx, fmt.Sprintf(` + INSERT INTO mercury_transmit_requests (payload, payload_hash, config_digest, epoch, round, extra_hash, job_id, feed_id, server_url) + VALUES %s ON CONFLICT (server_url, payload_hash) DO NOTHING - `, serverURL, req.Payload, hashPayload(req.Payload), reportCtx.ConfigDigest[:], reportCtx.Epoch, reportCtx.Round, reportCtx.ExtraHash[:], jobID, feedID[:]) + `, strings.Join(values, ",")), args...) }() go func() { diff --git a/core/services/relay/evm/mercury/orm_test.go b/core/services/relay/evm/mercury/orm_test.go index f928acdb538..f3ff70cdced 100644 --- a/core/services/relay/evm/mercury/orm_test.go +++ b/core/services/relay/evm/mercury/orm_test.go @@ -48,15 +48,15 @@ func TestORM(t *testing.T) { // Test insert and get requests. // s1 - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[0]}, jobID, reportContexts[0]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[0]}, jobID, reportContexts[0]) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[1]}, jobID, reportContexts[1]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[1]}, jobID, reportContexts[1]) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[2]}, jobID, reportContexts[2]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[2]}, jobID, reportContexts[2]) require.NoError(t, err) // s2 - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[0]) + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[0]) require.NoError(t, err) transmissions, err := orm.GetTransmitRequests(ctx, sURL, jobID) @@ -119,7 +119,7 @@ func TestORM(t *testing.T) { require.Empty(t, transmissions) // More inserts. - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) require.NoError(t, err) transmissions, err = orm.GetTransmitRequests(ctx, sURL, jobID) @@ -129,9 +129,9 @@ func TestORM(t *testing.T) { }) // Duplicate requests are ignored. - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[3]}, jobID, reportContexts[3]) require.NoError(t, err) transmissions, err = orm.GetTransmitRequests(ctx, sURL, jobID) @@ -150,6 +150,51 @@ func TestORM(t *testing.T) { require.Len(t, transmissions, 1) } +func TestORM_InsertTransmitRequest_MultipleServerURLs(t *testing.T) { + ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) + + jobID := rand.Int32() // foreign key constraints disabled so value doesn't matter + pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) + pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) + orm := NewORM(db) + feedID := sampleFeedID + + reports := sampleReports + reportContexts := make([]ocrtypes.ReportContext, 4) + for i := range reportContexts { + reportContexts[i] = ocrtypes.ReportContext{ + ReportTimestamp: ocrtypes.ReportTimestamp{ + ConfigDigest: ocrtypes.ConfigDigest{'1'}, + Epoch: 10, + Round: uint8(i), + }, + ExtraHash: [32]byte{'2'}, + } + } + err := orm.InsertTransmitRequest(ctx, []string{sURL, sURL2, sURL3}, &pb.TransmitRequest{Payload: reports[0]}, jobID, reportContexts[0]) + require.NoError(t, err) + + transmissions, err := orm.GetTransmitRequests(ctx, sURL, jobID) + require.NoError(t, err) + require.Len(t, transmissions, 1) + assert.Equal(t, transmissions[0], &Transmission{Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: reportContexts[0]}) + + transmissions, err = orm.GetTransmitRequests(ctx, sURL2, jobID) + require.NoError(t, err) + require.Len(t, transmissions, 1) + assert.Equal(t, transmissions[0], &Transmission{Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: reportContexts[0]}) + + transmissions, err = orm.GetTransmitRequests(ctx, sURL3, jobID) + require.NoError(t, err) + require.Len(t, transmissions, 1) + assert.Equal(t, transmissions[0], &Transmission{Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: reportContexts[0]}) + + l, err := orm.LatestReport(testutils.Context(t), feedID) + require.NoError(t, err) + assert.Equal(t, reports[0], l) +} + func TestORM_PruneTransmitRequests(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) @@ -173,18 +218,18 @@ func TestORM_PruneTransmitRequests(t *testing.T) { } // s1 - err := orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 1)) + err := orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 1)) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 2)) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 2)) require.NoError(t, err) // s2 - should not be touched - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 0)) + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 0)) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 1)) + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(1, 1)) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 2)) + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 2)) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(1, 3)) + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(1, 3)) require.NoError(t, err) // Max size greater than number of records, expect no-op @@ -220,9 +265,9 @@ func TestORM_PruneTransmitRequests(t *testing.T) { {Req: &pb.TransmitRequest{Payload: reports[0]}, ReportCtx: makeReportContext(1, 1)}, }, transmissions) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(2, 1)) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(2, 1)) require.NoError(t, err) - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[3]}, jobID, makeReportContext(2, 2)) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[3]}, jobID, makeReportContext(2, 2)) require.NoError(t, err) // Max size is table size - 1, expect the oldest row to be pruned. @@ -266,13 +311,13 @@ func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { } } - err := orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext( + err := orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext( 0, 0, )) require.NoError(t, err) // this should be ignored, because report context is the same - err = orm.InsertTransmitRequest(ctx, sURL2, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext( + err = orm.InsertTransmitRequest(ctx, []string{sURL2}, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext( 0, 0, )) require.NoError(t, err) @@ -282,7 +327,7 @@ func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { assert.Equal(t, reports[0], l) t.Run("replaces if epoch and round are larger", func(t *testing.T) { - err = orm.InsertTransmitRequest(ctx, "foo", &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 1)) + err = orm.InsertTransmitRequest(ctx, []string{"foo"}, &pb.TransmitRequest{Payload: reports[1]}, jobID, makeReportContext(1, 1)) require.NoError(t, err) l, err = orm.LatestReport(testutils.Context(t), feedID) @@ -290,7 +335,7 @@ func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { assert.Equal(t, reports[1], l) }) t.Run("replaces if epoch is the same but round is greater", func(t *testing.T) { - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(1, 2)) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[2]}, jobID, makeReportContext(1, 2)) require.NoError(t, err) l, err = orm.LatestReport(testutils.Context(t), feedID) @@ -298,7 +343,7 @@ func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { assert.Equal(t, reports[2], l) }) t.Run("replaces if epoch is larger but round is smaller", func(t *testing.T) { - err = orm.InsertTransmitRequest(ctx, "bar", &pb.TransmitRequest{Payload: reports[3]}, jobID, makeReportContext(2, 1)) + err = orm.InsertTransmitRequest(ctx, []string{"bar"}, &pb.TransmitRequest{Payload: reports[3]}, jobID, makeReportContext(2, 1)) require.NoError(t, err) l, err = orm.LatestReport(testutils.Context(t), feedID) @@ -306,7 +351,7 @@ func TestORM_InsertTransmitRequest_LatestReport(t *testing.T) { assert.Equal(t, reports[3], l) }) t.Run("does not overwrite if epoch/round is the same", func(t *testing.T) { - err = orm.InsertTransmitRequest(ctx, sURL, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(2, 1)) + err = orm.InsertTransmitRequest(ctx, []string{sURL}, &pb.TransmitRequest{Payload: reports[0]}, jobID, makeReportContext(2, 1)) require.NoError(t, err) l, err = orm.LatestReport(testutils.Context(t), feedID) diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index d49d0d4ed01..38576174423 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -69,7 +69,7 @@ func (pm *PersistenceManager) Close() error { } func (pm *PersistenceManager) Insert(ctx context.Context, req *pb.TransmitRequest, reportCtx ocrtypes.ReportContext) error { - return pm.orm.InsertTransmitRequest(ctx, pm.serverURL, req, pm.jobID, reportCtx) + return pm.orm.InsertTransmitRequest(ctx, []string{pm.serverURL}, req, pm.jobID, reportCtx) } func (pm *PersistenceManager) Delete(ctx context.Context, req *pb.TransmitRequest) error { diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 7ba5f5df606..70da93f4525 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -18,6 +18,7 @@ import ( pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "golang.org/x/exp/maps" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" @@ -110,6 +111,7 @@ type mercuryTransmitter struct { lggr logger.Logger cfg TransmitterConfig + orm ORM servers map[string]*server codec TransmitterReportDecoder @@ -302,6 +304,7 @@ func NewTransmitter(lggr logger.Logger, cfg TransmitterConfig, clients map[strin services.StateMachine{}, lggr.Named("MercuryTransmitter").With("feedID", feedIDHex), cfg, + orm, servers, codec, triggerCapability, @@ -404,14 +407,14 @@ func (mt *mercuryTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.R mt.lggr.Tracew("Transmit enqueue", "req.Payload", req.Payload, "report", report, "reportCtx", reportCtx, "signatures", signatures) + if err := mt.orm.InsertTransmitRequest(ctx, maps.Keys(mt.servers), req, mt.jobID, reportCtx); err != nil { + return err + } + g := new(errgroup.Group) for _, s := range mt.servers { s := s // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { - if err := s.pm.Insert(ctx, req, reportCtx); err != nil { - s.transmitQueueInsertErrorCount.Inc() - return err - } if ok := s.q.Push(req, reportCtx); !ok { s.transmitQueuePushErrorCount.Inc() return errors.New("transmit queue is closed") From a0e7b7cdd63ecb3f4d8e0ca3f5a4111703760c9b Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 14 May 2024 11:28:04 -0400 Subject: [PATCH 03/17] Add Transmit debug logging back in (#13128) --- .changeset/nine-plants-crash.md | 5 +++++ core/services/relay/evm/mercury/transmitter.go | 11 ++++++++--- core/services/relay/evm/mercury/transmitter_test.go | 4 ++++ .../relay/evm/mercury/v1/reportcodec/report_codec.go | 8 ++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 .changeset/nine-plants-crash.md diff --git a/.changeset/nine-plants-crash.md b/.changeset/nine-plants-crash.md new file mode 100644 index 00000000000..06a7c9bb309 --- /dev/null +++ b/.changeset/nine-plants-crash.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal improve mercury tranmission debugging diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 70da93f4525..415ecbb1787 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -97,6 +97,7 @@ type ConfigTracker interface { type TransmitterReportDecoder interface { BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) + ObservationTimestampFromReport(report ocrtypes.Report) (uint32, error) } var _ Transmitter = (*mercuryTransmitter)(nil) @@ -255,7 +256,7 @@ func (s *server) runQueueLoop(stopCh services.StopChan, wg *sync.WaitGroup, feed b.Reset() if res.Error == "" { s.transmitSuccessCount.Inc() - s.lggr.Debugw("Transmit report success", "payload", hexutil.Encode(t.Req.Payload), "response", res, "reportCtx", t.ReportCtx) + s.lggr.Debugw("Transmit report success", "payload", hexutil.Encode(t.Req.Payload), "response", res, "repts", t.ReportCtx.ReportTimestamp) } else { // We don't need to retry here because the mercury server // has confirmed it received the report. We only need to retry @@ -264,7 +265,7 @@ func (s *server) runQueueLoop(stopCh services.StopChan, wg *sync.WaitGroup, feed case DuplicateReport: s.transmitSuccessCount.Inc() s.transmitDuplicateCount.Inc() - s.lggr.Debugw("Transmit report success; duplicate report", "payload", hexutil.Encode(t.Req.Payload), "response", res, "reportCtx", t.ReportCtx) + s.lggr.Debugw("Transmit report success; duplicate report", "payload", hexutil.Encode(t.Req.Payload), "response", res, "repts", t.ReportCtx.ReportTimestamp) default: transmitServerErrorCount.WithLabelValues(feedIDHex, fmt.Sprintf("%d", res.Code)).Inc() s.lggr.Errorw("Transmit report failed; mercury server returned error", "response", res, "reportCtx", t.ReportCtx, "err", res.Error, "code", res.Code) @@ -405,7 +406,11 @@ func (mt *mercuryTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.R Payload: payload, } - mt.lggr.Tracew("Transmit enqueue", "req.Payload", req.Payload, "report", report, "reportCtx", reportCtx, "signatures", signatures) + ts, err := mt.codec.ObservationTimestampFromReport(report) + if err != nil { + mt.lggr.Warnw("Failed to get observation timestamp from report", "err", err) + } + mt.lggr.Debugw("Transmit enqueue", "req.Payload", hexutil.Encode(req.Payload), "report", report, "repts", reportCtx.ReportTimestamp, "signatures", signatures, "observationsTimestamp", ts) if err := mt.orm.InsertTransmitRequest(ctx, maps.Keys(mt.servers), req, mt.jobID, reportCtx); err != nil { return err diff --git a/core/services/relay/evm/mercury/transmitter_test.go b/core/services/relay/evm/mercury/transmitter_test.go index b286509e0ab..38d1eb621d5 100644 --- a/core/services/relay/evm/mercury/transmitter_test.go +++ b/core/services/relay/evm/mercury/transmitter_test.go @@ -216,6 +216,10 @@ func (m *mockCodec) BenchmarkPriceFromReport(_ ocrtypes.Report) (*big.Int, error return m.val, m.err } +func (m *mockCodec) ObservationTimestampFromReport(report ocrtypes.Report) (uint32, error) { + return 0, nil +} + func Test_MercuryTransmitter_LatestPrice(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index 8f2eac59c33..f4c6af32b8e 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -98,3 +98,11 @@ func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int } return decoded.BenchmarkPrice, nil } + +func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (uint32, error) { + decoded, err := r.Decode(report) + if err != nil { + return 0, err + } + return decoded.ObservationsTimestamp, nil +} From e778a3202b4d8761ffc44b790196d9a580fede1c Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Tue, 14 May 2024 16:25:04 -0400 Subject: [PATCH 04/17] AUTO-10539: improve offchain config logging (#13174) * AUTO-10539: improve offchain config length check * add changeset * update changeset * update * update * add offchain config log field * update * update --- .changeset/funny-monkeys-heal.md | 6 ++++++ .../ocr2keeper/evmregistry/v21/gasprice/gasprice.go | 7 +++++-- .../ocr2keeper/evmregistry/v21/registry_check_pipeline.go | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/funny-monkeys-heal.md diff --git a/.changeset/funny-monkeys-heal.md b/.changeset/funny-monkeys-heal.md new file mode 100644 index 00000000000..6267569432e --- /dev/null +++ b/.changeset/funny-monkeys-heal.md @@ -0,0 +1,6 @@ +--- +"chainlink": patch +--- + +#changed: +AUTO-10539: adjust logging for offchain config and gas control diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go index 2c376443fa5..f84a48c1ff8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go @@ -4,6 +4,8 @@ import ( "context" "math/big" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -27,17 +29,18 @@ type UpkeepOffchainConfig struct { // CheckGasPrice retrieves the current gas price and compare against the max gas price configured in upkeep's offchain config // any errors in offchain config decoding will result in max gas price check disabled func CheckGasPrice(ctx context.Context, upkeepId *big.Int, offchainConfigBytes []byte, ge gas.EvmFeeEstimator, lggr logger.Logger) encoding.UpkeepFailureReason { + // check for empty offchain config if len(offchainConfigBytes) == 0 { return encoding.UpkeepFailureReasonNone } var offchainConfig UpkeepOffchainConfig if err := cbor.ParseDietCBORToStruct(offchainConfigBytes, &offchainConfig); err != nil { - lggr.Errorw("failed to parse upkeep offchain config, gas price check is disabled", "upkeepId", upkeepId.String(), "err", err) + lggr.Warnw("failed to parse upkeep offchain config, gas price check is disabled", "offchainconfig", hexutil.Encode(offchainConfigBytes), "upkeepId", upkeepId.String(), "err", err) return encoding.UpkeepFailureReasonNone } if offchainConfig.MaxGasPrice == nil || offchainConfig.MaxGasPrice.Int64() <= 0 { - lggr.Warnw("maxGasPrice is not configured or incorrectly configured in upkeep offchain config, gas price check is disabled", "upkeepId", upkeepId.String()) + lggr.Debugw("maxGasPrice is not configured or incorrectly configured in upkeep offchain config, gas price check is disabled", "offchainconfig", hexutil.Encode(offchainConfigBytes), "upkeepId", upkeepId.String()) return encoding.UpkeepFailureReasonNone } lggr.Debugf("successfully decode offchain config for %s, max gas price is %s", upkeepId.String(), offchainConfig.MaxGasPrice.String()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go index e341730c794..491099496cb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go @@ -313,7 +313,7 @@ func (r *EvmRegistry) simulatePerformUpkeeps(ctx context.Context, checkResults [ } fr := gasprice.CheckGasPrice(ctx, upkeepId, oc, r.ge, r.lggr) if uint8(fr) == uint8(encoding.UpkeepFailureReasonGasPriceTooHigh) { - r.lggr.Infof("upkeep %s upkeep failure reason is %d", upkeepId, fr) + r.lggr.Debugf("upkeep %s upkeep failure reason is %d", upkeepId, fr) checkResults[i].Eligible = false checkResults[i].Retryable = false checkResults[i].IneligibilityReason = uint8(fr) From 4f502c9fd0fea458647bb345f5c0da995f3b6cb1 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Tue, 14 May 2024 15:55:47 -0700 Subject: [PATCH 05/17] [KS-196] Use Aggregator factory for OCR capability (#13199) Bump common to latest. --- .changeset/sweet-avocados-do.md | 5 ++++ core/capabilities/aggregator_factory.go | 21 ++++++++++++++++ core/capabilities/streams/codec.go | 24 +++++++++++++++++++ core/capabilities/syncer.go | 20 +++++++++------- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- plugins/cmd/chainlink-ocr3-capability/main.go | 6 +++-- 13 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 .changeset/sweet-avocados-do.md create mode 100644 core/capabilities/aggregator_factory.go create mode 100644 core/capabilities/streams/codec.go diff --git a/.changeset/sweet-avocados-do.md b/.changeset/sweet-avocados-do.md new file mode 100644 index 00000000000..4b8bb33a7e1 --- /dev/null +++ b/.changeset/sweet-avocados-do.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal Use Aggregator factory for OCR capability diff --git a/core/capabilities/aggregator_factory.go b/core/capabilities/aggregator_factory.go new file mode 100644 index 00000000000..bd0f0ceb237 --- /dev/null +++ b/core/capabilities/aggregator_factory.go @@ -0,0 +1,21 @@ +package capabilities + +import ( + "fmt" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/datafeeds" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/values" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" +) + +func NewAggregator(name string, config values.Map, lggr logger.Logger) (types.Aggregator, error) { + switch name { + case "data_feeds": + mc := streams.NewCodec() + return datafeeds.NewDataFeedsAggregator(config, mc, lggr) + default: + return nil, fmt.Errorf("aggregator %s not supported", name) + } +} diff --git a/core/capabilities/streams/codec.go b/core/capabilities/streams/codec.go new file mode 100644 index 00000000000..c04d7ee6a0c --- /dev/null +++ b/core/capabilities/streams/codec.go @@ -0,0 +1,24 @@ +package streams + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/mercury" + "github.com/smartcontractkit/chainlink-common/pkg/values" +) + +type Codec struct { +} + +func (c Codec) Unwrap(raw values.Value) ([]mercury.FeedReport, error) { + dest := []mercury.FeedReport{} + err := raw.UnwrapTo(&dest) + // TODO (KS-196): validate reports + return dest, err +} + +func (c Codec) Wrap(reports []mercury.FeedReport) (values.Value, error) { + return values.Wrap(reports) +} + +func NewCodec() Codec { + return Codec{} +} diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index 455582c4598..67e069c831d 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -2,12 +2,12 @@ package capabilities import ( "context" + "math/big" "slices" "sync" "time" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/mercury" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" "github.com/smartcontractkit/chainlink/v2/core/logger" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) @@ -97,9 +98,9 @@ func (s *registrySyncer) Start(ctx context.Context) error { } // NOTE: temporary hard-coded capabilities capId := "mercury-trigger" - triggerInfo := commoncap.CapabilityInfo{ + triggerInfo := capabilities.CapabilityInfo{ ID: capId, - CapabilityType: commoncap.CapabilityTypeTrigger, + CapabilityType: capabilities.CapabilityTypeTrigger, Description: "Remote Trigger", Version: "0.0.1", DON: &triggerCapabilityDonInfo, @@ -111,7 +112,8 @@ func (s *registrySyncer) Start(ctx context.Context) error { } if slices.Contains(workflowDONPeers, myId) { s.lggr.Info("member of a workflow DON - starting remote subscribers") - aggregator := triggers.NewMercuryRemoteAggregator(s.lggr) + codec := streams.NewCodec() + aggregator := triggers.NewMercuryRemoteAggregator(codec, s.lggr) triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, triggerCapabilityDonInfo, workflowDonInfo, s.dispatcher, aggregator, s.lggr) err = s.registry.Add(ctx, triggerCap) if err != nil { @@ -224,30 +226,30 @@ func (m *mockMercuryDataProducer) loop() { ticker := time.NewTicker(time.Duration(sleepSec) * time.Second) defer ticker.Stop() - prices := []int64{300000, 40000, 5000000} + prices := []*big.Int{big.NewInt(300000), big.NewInt(40000), big.NewInt(5000000)} for range ticker.C { for i := range prices { - prices[i] = prices[i] + 1 + prices[i].Add(prices[i], big.NewInt(1)) } reports := []mercury.FeedReport{ { FeedID: "0x1111111111111111111100000000000000000000000000000000000000000000", FullReport: []byte{0x11, 0xaa, 0xbb, 0xcc}, - BenchmarkPrice: prices[0], + BenchmarkPrice: prices[0].Bytes(), ObservationTimestamp: time.Now().Unix(), }, { FeedID: "0x2222222222222222222200000000000000000000000000000000000000000000", FullReport: []byte{0x22, 0xaa, 0xbb, 0xcc}, - BenchmarkPrice: prices[1], + BenchmarkPrice: prices[1].Bytes(), ObservationTimestamp: time.Now().Unix(), }, { FeedID: "0x3333333333333333333300000000000000000000000000000000000000000000", FullReport: []byte{0x33, 0xaa, 0xbb, 0xcc}, - BenchmarkPrice: prices[2], + BenchmarkPrice: prices[2].Bytes(), ObservationTimestamp: time.Now().Unix(), }, } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 2135c6833c9..542bdece430 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,7 +21,7 @@ require ( github.com/prometheus/client_golang v1.17.0 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 47254fb049d..a20ad0cce4f 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1185,8 +1185,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 h1:e/qJZHPDVcgv/bnydjyYBk3JYbDnxPaZ2LvTlfDZeXA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c h1:KiG8PAwUrdYn/AGBQ+B4p6erEUbEB+g6LJKhAaDjJ2s= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/go.mod b/go.mod index 1c44fac9da9..4250c0fef43 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab diff --git a/go.sum b/go.sum index 7cc88d7c0f4..5fa3897fc21 100644 --- a/go.sum +++ b/go.sum @@ -1171,8 +1171,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 h1:e/qJZHPDVcgv/bnydjyYBk3JYbDnxPaZ2LvTlfDZeXA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c h1:KiG8PAwUrdYn/AGBQ+B4p6erEUbEB+g6LJKhAaDjJ2s= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 17b62c4d844..50296d09764 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -27,7 +27,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c github.com/smartcontractkit/chainlink-testing-framework v1.28.11 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 893dff72823..04f7899c2d7 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1512,8 +1512,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 h1:e/qJZHPDVcgv/bnydjyYBk3JYbDnxPaZ2LvTlfDZeXA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c h1:KiG8PAwUrdYn/AGBQ+B4p6erEUbEB+g6LJKhAaDjJ2s= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 83ef49e1682..8840e1264f9 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,7 +16,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c github.com/smartcontractkit/chainlink-testing-framework v1.28.11 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 34d954a1604..05159b26ef5 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1502,8 +1502,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65 h1:e/qJZHPDVcgv/bnydjyYBk3JYbDnxPaZ2LvTlfDZeXA= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240509130051-b54aae6a8b65/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c h1:KiG8PAwUrdYn/AGBQ+B4p6erEUbEB+g6LJKhAaDjJ2s= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c/go.mod h1:sj0pjL+METqeYL9ibp0T8SXquymlaQsofa6bdfLgXX8= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/plugins/cmd/chainlink-ocr3-capability/main.go b/plugins/cmd/chainlink-ocr3-capability/main.go index 85767554a1c..c70a5a6f2ad 100644 --- a/plugins/cmd/chainlink-ocr3-capability/main.go +++ b/plugins/cmd/chainlink-ocr3-capability/main.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" ocr3rp "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -22,8 +23,9 @@ func main() { defer s.Stop() c := ocr3.Config{ - Logger: s.Logger, - EncoderFactory: evm.NewEVMEncoder, + Logger: s.Logger, + EncoderFactory: evm.NewEVMEncoder, + AggregatorFactory: capabilities.NewAggregator, } p := ocr3.NewOCR3(c) if err := p.Start(context.Background()); err != nil { From 6ee7c81a943d203b0a624936780d3948ef1b9326 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Wed, 15 May 2024 12:09:13 +0200 Subject: [PATCH 06/17] [TT-1140] Cl node test log scanner (#13161) * add back functionality that checks cl node logs after tests for errors * add comment, newer CTF version * use CTF release version * ignore expected errors in cl node logs * fix go.mod * fix load tests * fix lints * fix lints again * fix another vrfv2 log error * use CTF release version * [TT-922, TT-943] Migrate automation and log poller tests to Seth (#12688) * WIP#1 * fix load test * lints * lints again * uncomment tests * fix logtrigger mercury test * set privilege before starting consumer * WIP#2 * WIP#2 - with high concurrency upkeep registration fails * more or less working * WIP#4 * small fixes * fix lints * use latest Seth * Migrated keeper benchmark, kind of * migrate keeper smoke tests * bunch of optimisation * migrate automation chaos test * migrate log poller tests to Seth * use anysynced key with log poller * fix some of failing smoke tests * fix go mod * use correct Seth version * better automation some test structure * better automation some test structure * go mod * fix issues with missing LINK funds * fix keeper test * fix automation test * clean up, comments, migrate keeper benchmark test * mend * use latest Seth * cleanups, comments, etc * clean ups, automation tests + keeper tests now always test multiple contracts * use newer action version * debug results when upkeeps fails * run automation tests with post-failure debug * run automation tests with post-failure debug * better staleness report * more debug for basic automation tests * more assertions * try with sleep * increase performance check timeout to 3m * separate config from consumer start * more debug for performance chcek * try with just 1 contract * one more clean up * run keeper tests in CI to test them * solve automation load test registration failures * subscribe to headers in benchmark test to observe upkeeps * centralised ephemeral keys on testnet check, fixed keeper smoke tests, added root key buffer check * do not fail, when on testnet and ephemeral keys are !=0, set them 0 instead * don't fail in test config, display warning if eph addresses are set and set them to 0 * fix possible nil pointer, remove block range timeout, mutex for error appending * update seth version * use buffered channel to read subscription headers from EVM node * benchmark test increase RR mem and set DEBUG log level * use CTF's concurrent executor to deploy contracts in parallel * change architecture so that we have only 1 subscription and then we fan out the header to all goroutines; use SafeEVMHeader * benchmark test increase geth disk and gaslimit * decrease log level, latest seth and ctf * update CTF dependency * use concurrent executor in automation load test * remove local replace * add header subscription reconnect handling * print return funds error * limit automation load test deployment concurrency * latest Seth + fix gun * do not run keeper smoke tests on each commit anymore * add one more error message * use tagged CTF * use latest Seth * use latest Seth * fix go.mod * forget about smart reconnect, just do it in a loop * use latest Seth * check if context has error before executing any of contract calling wrapper functions * prettify code + latest Seth * update Seth * optional retrying of read-only contract calls; used only by keeper benchmark test * update Seth, estimate gas for funds sending * fix new automation test, update Seth to v1.0.7 * increase timeout * fix max price smoke test * fix CreateOCRKeeperJobs for v2.0 * remove resolved TODO * code review changes * code review changes * code review changes vol 2 * use CTF release version * bump mod version --------- Co-authored-by: anirudhwarrier <12178754+anirudhwarrier@users.noreply.github.com> * add exception to other chaos log poller smoke tests --------- Co-authored-by: anirudhwarrier <12178754+anirudhwarrier@users.noreply.github.com> --- .../actions/vrf/vrfv2/setup_steps.go | 16 +- .../actions/vrf/vrfv2plus/setup_steps.go | 15 +- .../docker/test_env/test_env_builder.go | 148 +++++++++++++++--- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- integration-tests/load/vrfv2/vrfv2_test.go | 4 +- .../load/vrfv2plus/vrfv2plus_test.go | 4 +- integration-tests/smoke/log_poller_test.go | 36 +++-- integration-tests/smoke/vrfv2_test.go | 27 +++- integration-tests/smoke/vrfv2plus_test.go | 39 +++-- .../universal/log_poller/helpers.go | 5 +- 13 files changed, 237 insertions(+), 69 deletions(-) diff --git a/integration-tests/actions/vrf/vrfv2/setup_steps.go b/integration-tests/actions/vrf/vrfv2/setup_steps.go index 5c441bf811e..c21ff0a11e6 100644 --- a/integration-tests/actions/vrf/vrfv2/setup_steps.go +++ b/integration-tests/actions/vrf/vrfv2/setup_steps.go @@ -320,7 +320,16 @@ func SetupVRFV2WrapperEnvironment( return wrapperContracts, &wrapperSubID, nil } -func SetupVRFV2Universe(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { +func SetupVRFV2Universe( + ctx context.Context, + t *testing.T, + testConfig tc.TestConfig, + chainID int64, + cleanupFn func(), + newEnvConfig vrfcommon.NewEnvConfig, + l zerolog.Logger, + chainlinkNodeLogScannerSettings test_env.ChainlinkNodeLogScannerSettings, +) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { var ( env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts @@ -334,7 +343,7 @@ func SetupVRFV2Universe(ctx context.Context, t *testing.T, testConfig tc.TestCon return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 for Existing env", err) } } else { - vrfContracts, vrfKey, env, nodeTypeToNodeMap, err = SetupVRFV2ForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l) + vrfContracts, vrfKey, env, nodeTypeToNodeMap, err = SetupVRFV2ForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 for New env", err) } @@ -350,17 +359,20 @@ func SetupVRFV2ForNewEnv( cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger, + chainlinkNodeLogScannerSettings test_env.ChainlinkNodeLogScannerSettings, ) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error building ethereum network config", err) } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&testConfig). WithPrivateEthereumNetwork(network.EthereumNetworkConfig). WithCLNodes(len(newEnvConfig.NodesToCreate)). WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). + WithChainlinkNodeLogScanner(chainlinkNodeLogScannerSettings). WithCustomCleanup(cleanupFn). Build() diff --git a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go index ab973ffe110..fdb5592767a 100644 --- a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go @@ -371,7 +371,16 @@ func SetupVRFV2PlusWrapperEnvironment( return wrapperContracts, wrapperSubID, nil } -func SetupVRFV2PlusUniverse(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { +func SetupVRFV2PlusUniverse( + ctx context.Context, + t *testing.T, + testConfig tc.TestConfig, + chainID int64, + cleanupFn func(), + newEnvConfig vrfcommon.NewEnvConfig, + l zerolog.Logger, + chainlinkNodeLogScannerSettings test_env.ChainlinkNodeLogScannerSettings, +) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { var ( env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts @@ -385,7 +394,7 @@ func SetupVRFV2PlusUniverse(ctx context.Context, t *testing.T, testConfig tc.Tes return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 Plus for Existing env", err) } } else { - vrfContracts, vrfKey, env, nodeTypeToNode, err = SetupVRFV2PlusForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l) + vrfContracts, vrfKey, env, nodeTypeToNode, err = SetupVRFV2PlusForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 Plus for New env", err) } @@ -401,6 +410,7 @@ func SetupVRFV2PlusForNewEnv( cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger, + chainlinkNodeLogScannerSettings test_env.ChainlinkNodeLogScannerSettings, ) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) if err != nil { @@ -412,6 +422,7 @@ func SetupVRFV2PlusForNewEnv( WithPrivateEthereumNetwork(network.EthereumNetworkConfig). WithCLNodes(len(newEnvConfig.NodesToCreate)). WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). + WithChainlinkNodeLogScanner(chainlinkNodeLogScannerSettings). WithCustomCleanup(cleanupFn). Build() if err != nil { diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 19617b0c5f7..0089ce0778a 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -1,15 +1,19 @@ package test_env import ( - "errors" + "context" "fmt" "math/big" "os" + "slices" "testing" + "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/seth" + "go.uber.org/zap/zapcore" + "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" @@ -17,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -35,38 +40,65 @@ const ( CleanUpTypeCustom CleanUpType = "custom" ) +type ChainlinkNodeLogScannerSettings struct { + FailingLogLevel zapcore.Level + Threshold uint + AllowedMessages []testreporters.AllowedLogMessage +} + type CLTestEnvBuilder struct { - hasLogStream bool - hasKillgrave bool - hasForwarders bool - hasSeth bool - hasEVMClient bool - clNodeConfig *chainlink.Config - secretsConfig string - clNodesCount int - clNodesOpts []func(*ClNode) - customNodeCsaKeys []string - defaultNodeCsaKeys []string - l zerolog.Logger - t *testing.T - te *CLClusterTestEnv - isNonEVM bool - cleanUpType CleanUpType - cleanUpCustomFn func() - chainOptionsFn []ChainOption - evmNetworkOption []EVMNetworkOption - privateEthereumNetworks []*ctf_config.EthereumNetworkConfig - testConfig ctf_config.GlobalTestConfig + hasLogStream bool + hasKillgrave bool + hasForwarders bool + hasSeth bool + hasEVMClient bool + clNodeConfig *chainlink.Config + secretsConfig string + clNodesCount int + clNodesOpts []func(*ClNode) + customNodeCsaKeys []string + defaultNodeCsaKeys []string + l zerolog.Logger + t *testing.T + te *CLClusterTestEnv + isNonEVM bool + cleanUpType CleanUpType + cleanUpCustomFn func() + chainOptionsFn []ChainOption + evmNetworkOption []EVMNetworkOption + privateEthereumNetworks []*ctf_config.EthereumNetworkConfig + testConfig ctf_config.GlobalTestConfig + chainlinkNodeLogScannerSettings *ChainlinkNodeLogScannerSettings /* funding */ ETHFunds *big.Float } +var DefaultAllowedMessages = []testreporters.AllowedLogMessage{ + testreporters.NewAllowedLogMessage("Failed to get LINK balance", "Happens only when we deploy LINK token for test purposes. Harmless.", zapcore.ErrorLevel, testreporters.WarnAboutAllowedMsgs_No), +} + +var DefaultChainlinkNodeLogScannerSettings = ChainlinkNodeLogScannerSettings{ + FailingLogLevel: zapcore.DPanicLevel, + Threshold: 1, // we want to fail on the first concerning log + AllowedMessages: DefaultAllowedMessages, +} + +func GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(extraAllowedMessages ...testreporters.AllowedLogMessage) ChainlinkNodeLogScannerSettings { + allowedMessages := append(DefaultAllowedMessages, extraAllowedMessages...) + return ChainlinkNodeLogScannerSettings{ + FailingLogLevel: zapcore.DPanicLevel, + Threshold: 1, + AllowedMessages: allowedMessages, + } +} + func NewCLTestEnvBuilder() *CLTestEnvBuilder { return &CLTestEnvBuilder{ - l: log.Logger, - hasLogStream: true, - hasEVMClient: true, + l: log.Logger, + hasLogStream: true, + hasEVMClient: true, + chainlinkNodeLogScannerSettings: &DefaultChainlinkNodeLogScannerSettings, } } @@ -114,6 +146,16 @@ func (b *CLTestEnvBuilder) WithoutLogStream() *CLTestEnvBuilder { return b } +func (b *CLTestEnvBuilder) WithoutChainlinkNodeLogScanner() *CLTestEnvBuilder { + b.chainlinkNodeLogScannerSettings = &ChainlinkNodeLogScannerSettings{} + return b +} + +func (b *CLTestEnvBuilder) WithChainlinkNodeLogScanner(settings ChainlinkNodeLogScannerSettings) *CLTestEnvBuilder { + b.chainlinkNodeLogScannerSettings = &settings + return b +} + func (b *CLTestEnvBuilder) WithCLNodes(clNodesCount int) *CLTestEnvBuilder { b.clNodesCount = clNodesCount return b @@ -231,6 +273,12 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.hasLogStream { + loggingConfig := b.testConfig.GetLoggingConfig() + // we need to enable logging to file if we want to scan logs + if b.chainlinkNodeLogScannerSettings != nil && !slices.Contains(loggingConfig.LogStream.LogTargets, string(logstream.File)) { + b.l.Debug().Msg("Enabling logging to file in order to support Chainlink node log scanning") + loggingConfig.LogStream.LogTargets = append(loggingConfig.LogStream.LogTargets, string(logstream.File)) + } b.te.LogStream, err = logstream.NewLogStream(b.te.t, b.testConfig.GetLoggingConfig()) if err != nil { return nil, err @@ -279,11 +327,55 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { b.l.Info().Str("Absolute path", logPath).Msg("LogStream logs folder location") } + var scanClNodeLogs = func() { + //filter out non-cl logs + logLocation := b.te.LogStream.GetLogLocation() + logFiles, err := testreporters.FindAllLogFilesToScan(logLocation, "cl-node") + if err != nil { + b.l.Warn().Err(err).Msg("Error looking for Chainlink Node log files to scan") + } else { + // we ignore the context returned by errgroup here, since we have no way of interrupting ongoing scanning of logs + verifyLogsGroup, _ := errgroup.WithContext(context.Background()) + for _, f := range logFiles { + file := f + verifyLogsGroup.Go(func() error { + logErr := testreporters.VerifyLogFile(file, b.chainlinkNodeLogScannerSettings.FailingLogLevel, b.chainlinkNodeLogScannerSettings.Threshold, b.chainlinkNodeLogScannerSettings.AllowedMessages...) + if logErr != nil { + return errors.Wrapf(logErr, "Found a concerning log in %s", file.Name()) + } + return nil + }) + } + if err := verifyLogsGroup.Wait(); err != nil { + b.l.Error().Err(err).Msg("Found a concerning log. Failing test.") + b.t.Fatalf("Found a concerning log in Chainklink Node logs: %v", err) + } + } + b.l.Info().Msg("Finished scanning Chainlink Node logs for concerning errors") + } + if b.t.Failed() || *b.testConfig.GetLoggingConfig().TestLogCollect { // we can't do much if this fails, so we just log the error in logstream - _ = b.te.LogStream.FlushAndShutdown() + flushErr := b.te.LogStream.FlushAndShutdown() + if flushErr != nil { + b.l.Error().Err(flushErr).Msg("Error flushing and shutting down LogStream") + return + } b.te.LogStream.PrintLogTargetsLocations() b.te.LogStream.SaveLogLocationInTestSummary() + + // if test hasn't failed, but we have chainlinkNodeLogScannerSettings, we should check the logs + if !b.t.Failed() && b.chainlinkNodeLogScannerSettings != nil { + scanClNodeLogs() + } + } else if b.chainlinkNodeLogScannerSettings != nil { + flushErr := b.te.LogStream.FlushAndShutdown() + if flushErr != nil { + b.l.Error().Err(flushErr).Msg("Error flushing and shutting down LogStream") + return + } + + scanClNodeLogs() } }) } @@ -303,6 +395,10 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } + if b.te.LogStream == nil && b.chainlinkNodeLogScannerSettings != nil { + log.Warn().Msg("Chainlink node log scanner settings provided, but LogStream is not enabled. Ignoring Chainlink node log scanner settings, as no logs will be available.") + } + // in this case we will use the builder only to start chains, not the cluster, because currently we support only 1 network config per cluster if len(b.privateEthereumNetworks) > 1 { b.te.rpcProviders = make(map[int64]*test_env.RpcProvider) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 50296d09764..c831f3f181d 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -28,7 +28,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c - github.com/smartcontractkit/chainlink-testing-framework v1.28.11 + github.com/smartcontractkit/chainlink-testing-framework v1.28.12 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 04f7899c2d7..dfacb294fd9 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1524,8 +1524,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240510181707-46b1311a5a8 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240510181707-46b1311a5a83/go.mod h1:RdAtOeBUWq2zByw2kEbwPlXaPIb7YlaDOmnn+nVUBJI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240508155030-1024f2b55c69 h1:ssh/w3oXWu+C6bE88GuFRC1+0Bx/4ihsbc80XMLrl2k= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240508155030-1024f2b55c69/go.mod h1:VsfjhvWgjxqWja4q+FlXEtX5lu8BSxn10xRo6gi948g= -github.com/smartcontractkit/chainlink-testing-framework v1.28.11 h1:6IcgmK/6UAfmcOYSiXudVlOa60MkbObTxA68hSJT4O4= -github.com/smartcontractkit/chainlink-testing-framework v1.28.11/go.mod h1:x1zDOz8zcLjEvs9fNA9y/DMguLam/2+CJdpxX0+rM8A= +github.com/smartcontractkit/chainlink-testing-framework v1.28.12 h1:15ssos9DvWekvj6JjmiPjTYsj/uw12HvTWlm1FHdYaA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.12/go.mod h1:x1zDOz8zcLjEvs9fNA9y/DMguLam/2+CJdpxX0+rM8A= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 h1:fX/xmGm1GBsD1ZZnooNT+eWA0hiTAqFlHzOC5CY4dy8= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 8840e1264f9..782408dff3c 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -17,7 +17,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 github.com/smartcontractkit/chainlink-common v0.1.7-0.20240514153505-0ddba5aa4d2c - github.com/smartcontractkit/chainlink-testing-framework v1.28.11 + github.com/smartcontractkit/chainlink-testing-framework v1.28.12 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 05159b26ef5..00112420705 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1514,8 +1514,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240510181707-46b1311a5a8 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240510181707-46b1311a5a83/go.mod h1:RdAtOeBUWq2zByw2kEbwPlXaPIb7YlaDOmnn+nVUBJI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240508155030-1024f2b55c69 h1:ssh/w3oXWu+C6bE88GuFRC1+0Bx/4ihsbc80XMLrl2k= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240508155030-1024f2b55c69/go.mod h1:VsfjhvWgjxqWja4q+FlXEtX5lu8BSxn10xRo6gi948g= -github.com/smartcontractkit/chainlink-testing-framework v1.28.11 h1:6IcgmK/6UAfmcOYSiXudVlOa60MkbObTxA68hSJT4O4= -github.com/smartcontractkit/chainlink-testing-framework v1.28.11/go.mod h1:x1zDOz8zcLjEvs9fNA9y/DMguLam/2+CJdpxX0+rM8A= +github.com/smartcontractkit/chainlink-testing-framework v1.28.12 h1:15ssos9DvWekvj6JjmiPjTYsj/uw12HvTWlm1FHdYaA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.12/go.mod h1:x1zDOz8zcLjEvs9fNA9y/DMguLam/2+CJdpxX0+rM8A= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449 h1:fX/xmGm1GBsD1ZZnooNT+eWA0hiTAqFlHzOC5CY4dy8= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240328204215-ac91f55f1449/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index ca41dd40ea9..a62e4cdd552 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -99,7 +99,7 @@ func TestVRFV2Performance(t *testing.T) { UseTestCoordinator: true, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) @@ -243,7 +243,7 @@ func TestVRFV2BHSPerformance(t *testing.T) { UseTestCoordinator: true, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index e24b2ff17d8..2496e2b692b 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -97,7 +97,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := testEnv.GetEVMClient(chainID) @@ -240,7 +240,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := testEnv.GetEVMClient(chainID) diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index f75dfe96c7a..04327471e7f 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -11,9 +11,11 @@ import ( "github.com/onsi/gomega" "github.com/rs/zerolog" "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -25,45 +27,52 @@ import ( core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" ) +var logScannerSettings = test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(testreporters.NewAllowedLogMessage( + "SLOW SQL QUERY", + "It is expected, because we are pausing the Postgres container", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No, +)) + // consistency test with no network disruptions with approximate emission of 1500-1600 logs per second for ~110-120 seconds // 6 filters are registered func TestLogPollerFewFiltersFixedDepth(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, test_env.DefaultChainlinkNodeLogScannerSettings) } func TestLogPollerFewFiltersFinalityTag(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, test_env.DefaultChainlinkNodeLogScannerSettings) } // consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds // 900 filters are registered func TestLogPollerManyFiltersFixedDepth(t *testing.T) { t.Skip("Execute manually, when needed as it runs for a long time") - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, test_env.DefaultChainlinkNodeLogScannerSettings) } func TestLogPollerManyFiltersFinalityTag(t *testing.T) { t.Skip("Execute manually, when needed as it runs for a long time") - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, test_env.DefaultChainlinkNodeLogScannerSettings) } -// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds +// consistency test that introduces random disruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds // with approximate emission of 520-550 logs per second for ~110 seconds // 6 filters are registered func TestLogPollerWithChaosFixedDepth(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, logScannerSettings) } func TestLogPollerWithChaosFinalityTag(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, logScannerSettings) } func TestLogPollerWithChaosPostgresFixedDepth(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, logScannerSettings) } func TestLogPollerWithChaosPostgresFinalityTag(t *testing.T) { - executeBasicLogPollerTest(t) + executeBasicLogPollerTest(t, logScannerSettings) } // consistency test that registers filters after events were emitted and then triggers replay via API @@ -80,7 +89,7 @@ func TestLogPollerReplayFinalityTag(t *testing.T) { } // HELPER FUNCTIONS -func executeBasicLogPollerTest(t *testing.T) { +func executeBasicLogPollerTest(t *testing.T, logScannerSettings test_env.ChainlinkNodeLogScannerSettings) { testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) require.NoError(t, err, "Error getting config") overrideEphemeralAddressesCount(&testConfig) @@ -96,7 +105,7 @@ func executeBasicLogPollerTest(t *testing.T) { l := logging.GetTestLogger(t) coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - lpTestEnv := prepareEnvironment(l, t, &testConfig) + lpTestEnv := prepareEnvironment(l, t, &testConfig, logScannerSettings) testEnv := lpTestEnv.testEnv ctx := testcontext.Get(t) @@ -177,7 +186,7 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { l := logging.GetTestLogger(t) coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - lpTestEnv := prepareEnvironment(l, t, &testConfig) + lpTestEnv := prepareEnvironment(l, t, &testConfig, test_env.DefaultChainlinkNodeLogScannerSettings) testEnv := lpTestEnv.testEnv ctx := testcontext.Get(t) @@ -262,7 +271,7 @@ type logPollerEnvironment struct { // prepareEnvironment prepares environment for log poller tests by starting DON, private Ethereum network, // deploying registry and log emitter contracts and registering log triggered upkeeps -func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfig) logPollerEnvironment { +func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfig, logScannerSettings test_env.ChainlinkNodeLogScannerSettings) logPollerEnvironment { cfg := testConfig.LogPoller if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { l.Warn().Msg("No events to emit specified, using all events from log emitter contract") @@ -287,6 +296,7 @@ func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfi *cfg.General.BackupLogPollerBlockDelay, *cfg.General.UseFinalityTag, testConfig, + logScannerSettings, ) _, upkeepIDs := actions_seth.DeployConsumers( diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index ce9f448ee66..946a73f0e18 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -14,10 +14,12 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" @@ -75,7 +77,7 @@ func TestVRFv2Basic(t *testing.T) { UseTestCoordinator: false, } - testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) require.NoError(t, err, "Getting EVM client shouldn't fail") @@ -610,7 +612,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { UseTestCoordinator: false, } - testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) @@ -718,7 +720,7 @@ func TestVRFOwner(t *testing.T) { UseTestCoordinator: true, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) @@ -866,7 +868,7 @@ func TestVRFV2WithBHS(t *testing.T) { UseTestCoordinator: false, } - testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") evmClient, err := testEnv.GetEVMClient(chainID) @@ -1070,7 +1072,20 @@ func TestVRFV2NodeReorg(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + chainlinkNodeLogScannerSettings := test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages( + testreporters.NewAllowedLogMessage( + "This is a problem and either means a very deep re-org occurred", + "Test is expecting a reorg to occur", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No), + testreporters.NewAllowedLogMessage( + "Reorg greater than finality depth detected", + "Test is expecting a reorg to occur", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No), + ) + + env, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2 universe") evmClient, err := env.GetEVMClient(chainID) @@ -1232,7 +1247,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2 universe") evmClient, err := env.GetEVMClient(chainID) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 0ef4e716733..6a64d08569a 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -13,10 +13,12 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -76,7 +78,7 @@ func TestVRFv2Plus(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -775,7 +777,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -881,7 +883,7 @@ func TestVRFv2PlusMigration(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -1309,7 +1311,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -1532,8 +1534,14 @@ func TestVRFV2PlusWithBHF(t *testing.T) { UseTestCoordinator: false, } + chainlinkNodeLogScannerSettings := test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(testreporters.NewAllowedLogMessage( + "Pipeline error", + "Test is expecting this error to occur", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No)) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse( - testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err) evmClient, err := env.GetEVMClient(chainID) require.NoError(t, err, "Getting EVM client shouldn't fail") @@ -1679,7 +1687,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { config.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) config.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -1876,7 +1884,7 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) config.VRFv2Plus.General.MinimumConfirmations = ptr.Ptr[uint16](0) config.VRFv2Plus.General.VRFJobSimulationBlock = ptr.Ptr[string]("pending") - env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -1965,7 +1973,20 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + chainlinkNodeLogScannerSettings := test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages( + testreporters.NewAllowedLogMessage( + "This is a problem and either means a very deep re-org occurred", + "Test is expecting a reorg to occur", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No), + testreporters.NewAllowedLogMessage( + "Reorg greater than finality depth detected", + "Test is expecting a reorg to occur", + zapcore.DPanicLevel, + testreporters.WarnAboutAllowedMsgs_No), + ) + + env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") evmClient, err := env.GetEVMClient(chainID) @@ -2125,7 +2146,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { UseTestCoordinator: false, } - env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") evmClient, err := env.GetEVMClient(chainID) diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 07334aa79ae..d732ad4af5d 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -1013,7 +1013,7 @@ func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv <-guardChan wg.Done() current := i + 1 - l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, testConfig.LogPoller.ChaosConfig.ExperimentCount)).Msg("Done with experiment") + l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, *testConfig.LogPoller.ChaosConfig.ExperimentCount)).Msg("Done with experiment") }() chaosChan <- chaosPauseSyncFn(l, sethClient, testEnv.ClCluster, *testConfig.LogPoller.ChaosConfig.TargetComponent) time.Sleep(10 * time.Second) @@ -1115,6 +1115,7 @@ func SetupLogPollerTestDocker( backupPollingInterval uint64, finalityTagEnabled bool, testConfig *tc.TestConfig, + logScannerSettings test_env.ChainlinkNodeLogScannerSettings, ) ( *seth.Client, []*client.ChainlinkClient, @@ -1179,6 +1180,7 @@ func SetupLogPollerTestDocker( WithFunding(big.NewFloat(chainlinkNodeFunding)). WithChainOptions(logPolllerSettingsFn). EVMNetworkOptions(evmNetworkSettingsFn). + WithChainlinkNodeLogScanner(logScannerSettings). WithStandardCleanup(). WithSeth(). Build() @@ -1344,6 +1346,7 @@ func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock i } l.Warn(). Msg("At least one CL node did not have expected log count. Retrying...") + time.Sleep(10 * time.Second) } return allNodesLogCountMatches, nil From 09660df6410b53cc977216b88e894432b6361711 Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Wed, 15 May 2024 19:28:39 +0530 Subject: [PATCH 07/17] set OffchainConfig to empty (#13211) --- integration-tests/load/automationv2_1/automationv2_1_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index f8b1f1fc6d3..bd1fcfa1559 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -474,7 +474,7 @@ Load Config: TriggerType: uint8(1), CheckData: encodedCheckDataStruct, TriggerConfig: encodedLogTriggerConfig, - OffchainConfig: []byte("0"), + OffchainConfig: []byte(""), FundingAmount: automationDefaultLinkFunds, } l.Debug().Interface("Upkeep Config", upkeepConfig).Msg("Upkeep Config") From 37805cdcb7190af4991924aa51a50e31121c0a54 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 15 May 2024 10:42:31 -0400 Subject: [PATCH 08/17] Add example test for divide task (#13196) --- core/services/pipeline/task.divide_test.go | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/core/services/pipeline/task.divide_test.go b/core/services/pipeline/task.divide_test.go index a55abf6d41d..111087d2e3c 100644 --- a/core/services/pipeline/task.divide_test.go +++ b/core/services/pipeline/task.divide_test.go @@ -10,7 +10,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + bridgesMocks "github.com/smartcontractkit/chainlink/v2/core/bridges/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -193,3 +196,38 @@ func TestDivideTask_Overflow(t *testing.T) { assert.False(t, runInfo.IsRetryable) require.Equal(t, pipeline.ErrDivisionOverlow, errors.Cause(result.Error)) } + +func TestDivide_Example(t *testing.T) { + t.Parallel() + + dag := ` +ds1 [type=memo value=10000.1234] + +ds2 [type=memo value=100] + +div_by_ds2 [type=divide divisor="$(ds2)"] + +multiply [type=multiply times=10000 index=0] + +ds1->div_by_ds2->multiply; +` + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + btORM := bridgesMocks.NewORM(t) + r, _ := newRunner(t, db, btORM, cfg) + + spec := pipeline.Spec{DotDagSource: dag} + vars := pipeline.NewVarsFrom(nil) + + lggr := logger.TestLogger(t) + _, trrs, err := r.ExecuteRun(testutils.Context(t), spec, vars, lggr) + require.NoError(t, err) + + require.Len(t, trrs, 4) + + finalResult := trrs[3] + + assert.Nil(t, finalResult.Result.Error) + assert.Equal(t, "1000012.34", finalResult.Result.Value.(decimal.Decimal).String()) +} From dbc971ba57f563f3d0ca105fee588744ede988a6 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Wed, 15 May 2024 18:19:58 +0200 Subject: [PATCH 09/17] fix clean up order (#13205) --- integration-tests/docker/test_env/test_env.go | 1 + .../docker/test_env/test_env_builder.go | 72 +++++++++---------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 7cb618b8dae..f874b223e31 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -274,6 +274,7 @@ func (te *CLClusterTestEnv) handleNodeCoverageReports(testName string) error { if showHTMLCoverageReport || isCI { // Stop all nodes in the chainlink cluster. // This is needed to get go coverage profile from the node containers https://go.dev/doc/build-cover#FAQ + // TODO: fix this as it results in: ERR LOG AFTER TEST ENDED ... INF 🐳 Stopping container err := te.ClCluster.Stop() if err != nil { return err diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 0089ce0778a..707f7d9222b 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -23,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" - evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -283,42 +282,8 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if err != nil { return nil, err } - } - - if b.hasKillgrave { - if b.te.DockerNetwork == nil { - return nil, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("cannot start mock adapter without a network")) - } - - b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.DockerNetwork.Name}, "", test_env.WithLogStream(b.te.LogStream)) - - err = b.te.StartMockAdapter() - if err != nil { - return nil, err - } - } - - if b.t != nil { - b.te.WithTestInstance(b.t) - } - - switch b.cleanUpType { - case CleanUpTypeStandard: - b.t.Cleanup(func() { - // Cleanup test environment - if err := b.te.Cleanup(CleanupOpts{TestName: b.t.Name()}); err != nil { - b.l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) - case CleanUpTypeCustom: - b.t.Cleanup(b.cleanUpCustomFn) - case CleanUpTypeNone: - b.l.Warn().Msg("test environment won't be cleaned up") - case "": - return b.te, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("explicit cleanup type must be set when building test environment")) - } - if b.te.LogStream != nil { + // this clean up has to be added as the FIRST one, because cleanup functions are executed in reverse order (LIFO) if b.t != nil { b.t.Cleanup(func() { b.l.Info().Msg("Shutting down LogStream") @@ -379,7 +344,42 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } }) } + } + + if b.hasKillgrave { + if b.te.DockerNetwork == nil { + return nil, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("cannot start mock adapter without a network")) + } + + b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.DockerNetwork.Name}, "", test_env.WithLogStream(b.te.LogStream)) + + err = b.te.StartMockAdapter() + if err != nil { + return nil, err + } + } + + if b.t != nil { + b.te.WithTestInstance(b.t) + } + switch b.cleanUpType { + case CleanUpTypeStandard: + b.t.Cleanup(func() { + // Cleanup test environment + if err := b.te.Cleanup(CleanupOpts{TestName: b.t.Name()}); err != nil { + b.l.Error().Err(err).Msg("Error cleaning up test environment") + } + }) + case CleanUpTypeCustom: + b.t.Cleanup(b.cleanUpCustomFn) + case CleanUpTypeNone: + b.l.Warn().Msg("test environment won't be cleaned up") + case "": + return b.te, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("explicit cleanup type must be set when building test environment")) + } + + if b.te.LogStream != nil { // this is not the cleanest way to do this, but when we originally build ethereum networks, we don't have the logstream reference // so we need to rebuild them here and pass logstream to them for i := range b.privateEthereumNetworks { From 0ea99be6450d15d842c682ea13f8a3cbef98687b Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Wed, 15 May 2024 11:31:14 -0700 Subject: [PATCH 10/17] [KS-194] Send Streams reports to TriggerService (#13203) --- .../services/relay/evm/mercury/transmitter.go | 26 ++++++++++++++++++- .../relay/evm/mercury/transmitter_test.go | 14 ++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 415ecbb1787..3ddc285a6fc 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -24,6 +24,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + capMercury "github.com/smartcontractkit/chainlink-common/pkg/capabilities/mercury" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -380,6 +381,25 @@ func (mt *mercuryTransmitter) HealthReport() map[string]error { return report } +func (mt *mercuryTransmitter) sendToTrigger(report ocrtypes.Report, rs [][32]byte, ss [][32]byte, vs [32]byte) error { + var rsUnsized [][]byte + var ssUnsized [][]byte + for idx := range rs { + rsUnsized = append(rsUnsized, rs[idx][:]) + ssUnsized = append(ssUnsized, ss[idx][:]) + } + converted := capMercury.FeedReport{ + FeedID: mt.feedID.Hex(), + FullReport: report, + Rs: rsUnsized, + Ss: ssUnsized, + Vs: vs[:], + // NOTE: Skipping fields derived from FullReport, they will be filled out at a later stage + // after decoding and validating signatures. + } + return mt.triggerCapability.ProcessReport([]capMercury.FeedReport{converted}) +} + // Transmit sends the report to the on-chain smart contract's Transmit method. func (mt *mercuryTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signatures []ocrtypes.AttributedOnchainSignature) error { var rs [][32]byte @@ -395,7 +415,11 @@ func (mt *mercuryTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.R vs[i] = v } rawReportCtx := evmutil.RawReportContext(reportCtx) - // TODO(KS-194): send report to mt.triggerCapability.ProcessReport() + + if mt.triggerCapability != nil { + // Acting as a Capability - send report to trigger service and exit. + return mt.sendToTrigger(report, rs, ss, vs) + } payload, err := PayloadTypes.Pack(rawReportCtx, []byte(report), rs, ss, vs) if err != nil { diff --git a/core/services/relay/evm/mercury/transmitter_test.go b/core/services/relay/evm/mercury/transmitter_test.go index 38d1eb621d5..25f8a918e4e 100644 --- a/core/services/relay/evm/mercury/transmitter_test.go +++ b/core/services/relay/evm/mercury/transmitter_test.go @@ -13,6 +13,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -86,6 +87,19 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { require.Equal(t, mt.servers[sURL].q.pq.Len(), 1) assert.Subset(t, mt.servers[sURL].q.pq.Pop().(*Transmission).Req.Payload, report) }) + t.Run("v3 report transmission sent only to trigger service", func(t *testing.T) { + report := sampleV3Report + c := &mocks.MockWSRPCClient{} + clients[sURL] = c + triggerService := triggers.NewMercuryTriggerService(0, lggr) + mt := NewTransmitter(lggr, mockCfg{}, clients, sampleClientPubKey, jobID, sampleFeedID, orm, codec, triggerService) + // init the queue since we skipped starting transmitter + mt.servers[sURL].q.Init([]*Transmission{}) + err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) + require.NoError(t, err) + // queue is empty + require.Equal(t, mt.servers[sURL].q.pq.Len(), 0) + }) }) t.Run("with multiple mercury servers", func(t *testing.T) { From 286e6af42357dc08acc23659ac6d486dff458478 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 15 May 2024 21:24:25 +0200 Subject: [PATCH 11/17] Fix all solhint issues (#13185) * bump versions * fix vrf * fix shared * fix operatorforwarder * fix llo-feeds * fix l2ep * fix interfaces * fix functions * fix automation * changeset --- contracts/.changeset/fuzzy-bags-watch.md | 5 ++ contracts/.solhintignore | 2 + contracts/package.json | 8 +- contracts/pnpm-lock.yaml | 74 +++++++++---------- .../dev/v2_3/AutomationRegistrar2_3.sol | 1 + .../dev/v2_3/AutomationRegistryBase2_3.sol | 4 + .../dev/v2_3/AutomationRegistryLogicB2_3.sol | 2 + .../AutomationCompatibleInterface.sol | 1 + .../interfaces/IAutomationV21PlusCommon.sol | 2 + .../MigratableKeeperRegistryInterfaceV2.sol | 4 +- .../StreamsLookupCompatibleInterface.sol | 1 + .../interfaces/UpkeepTranscoderInterface.sol | 6 +- .../UpkeepTranscoderInterfaceV2.sol | 2 +- .../v0.8/automation/test/StructFactory.sol | 7 -- .../automation/v2_2/AutomationRegistry2_2.sol | 1 + .../v2_2/AutomationRegistryBase2_2.sol | 3 + .../functions/dev/v1_X/FunctionsRouter.sol | 1 + .../dev/v1_X/mocks/FunctionsV1EventsMock.sol | 2 + .../v0.8/functions/dev/v1_X/ocr/OCR2Base.sol | 1 + .../v0.8/functions/v1_1_0/ocr/OCR2Base.sol | 1 + .../v0.8/functions/v1_3_0/ocr/OCR2Base.sol | 1 + .../interfaces/ChainlinkRequestInterface.sol | 1 + .../src/v0.8/interfaces/ENSInterface.sol | 1 + .../v0.8/interfaces/FeedRegistryInterface.sol | 1 + .../src/v0.8/interfaces/FlagsInterface.sol | 1 + .../src/v0.8/interfaces/OperatorInterface.sol | 1 + .../src/v0.8/interfaces/OracleInterface.sol | 1 + .../src/v0.8/interfaces/PoRAddressList.sol | 1 + .../src/v0.8/interfaces/PointerInterface.sol | 1 + .../ArbitrumSequencerUptimeFeedInterface.sol | 1 + .../CrossDomainOwnableInterface.sol | 1 + .../interfaces/DelegateForwarderInterface.sol | 1 + .../l2ep/dev/interfaces/FlagsInterface.sol | 1 + .../dev/interfaces/ForwarderInterface.sol | 1 + .../OptimismSequencerUptimeFeedInterface.sol | 1 + .../ScrollSequencerUptimeFeedInterface.sol | 1 + .../v0.8/llo-feeds/dev/ChannelConfigStore.sol | 1 + .../test/testhelpers/Callback.sol | 1 + .../test/testhelpers/Consumer.sol | 1 + .../MaliciousMultiWordConsumer.sol | 2 + .../test/testhelpers/MockReceiver.sol | 1 + .../test/testhelpers/MultiWordConsumer.sol | 1 + contracts/src/v0.8/shared/ocr2/OCR2Base.sol | 1 + .../shared/test/helpers/ChainReaderTester.sol | 1 + .../src/v0.8/vrf/BatchBlockhashStore.sol | 1 + .../src/v0.8/vrf/BatchVRFCoordinatorV2.sol | 1 + contracts/src/v0.8/vrf/VRFV2Wrapper.sol | 1 + .../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol | 1 + .../VRFCoordinatorV2PlusUpgradedVersion.sol | 1 + .../VRFCoordinatorV2Plus_V2Example.sol | 1 + .../VRFV2PlusSingleConsumerExample.sol | 1 + .../VRFV2PlusWrapperConsumerExample.sol | 1 + .../VRFV2PlusWrapperLoadTestConsumer.sol | 1 + .../interfaces/BlockhashStoreInterface.sol | 1 + .../interfaces/VRFCoordinatorV2Interface.sol | 1 + .../vrf/interfaces/VRFV2WrapperInterface.sol | 1 + 56 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 contracts/.changeset/fuzzy-bags-watch.md delete mode 100644 contracts/src/v0.8/automation/test/StructFactory.sol diff --git a/contracts/.changeset/fuzzy-bags-watch.md b/contracts/.changeset/fuzzy-bags-watch.md new file mode 100644 index 00000000000..31e164df424 --- /dev/null +++ b/contracts/.changeset/fuzzy-bags-watch.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +fix solhint issues diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 7d0d5f40b29..ed395d93657 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -21,6 +21,8 @@ ./src/v0.8/automation/libraries/internal/Cron.sol ./src/v0.8/automation/AutomationForwarder.sol ./src/v0.8/automation/AutomationForwarderLogic.sol +./src/v0.8/automation/interfaces/v2_2/IAutomationRegistryMaster.sol +./src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol # Ignore tests / test helpers (for now) diff --git a/contracts/package.json b/contracts/package.json index 58204489ebe..306f8284b5c 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "pnpm publish --tag latest", - "solhint": "solhint --max-warnings 69 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 0 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -48,7 +48,7 @@ "@types/debug": "^4.1.12", "@types/deep-equal-in-any-order": "^1.0.3", "@types/mocha": "^10.0.6", - "@types/node": "^20.12.10", + "@types/node": "^20.12.11", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "abi-to-sol": "^0.6.6", @@ -66,7 +66,7 @@ "moment": "^2.30.1", "prettier": "^3.2.5", "prettier-plugin-solidity": "^1.3.1", - "solhint": "^4.5.4", + "solhint": "^5.0.1", "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1", "solhint-plugin-prettier": "^0.1.0", "ts-node": "^10.9.2", @@ -80,6 +80,6 @@ "@openzeppelin/contracts": "4.9.3", "@openzeppelin/contracts-upgradeable": "4.9.3", "@scroll-tech/contracts": "0.1.0", - "semver": "^7.6.1" + "semver": "^7.6.2" } } diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 13e7b29b96e..51a4ad6a4ca 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -27,8 +27,8 @@ dependencies: specifier: 0.1.0 version: 0.1.0 semver: - specifier: ^7.6.1 - version: 7.6.1 + specifier: ^7.6.2 + version: 7.6.2 devDependencies: '@ethereum-waffle/mock-contract': @@ -80,8 +80,8 @@ devDependencies: specifier: ^10.0.6 version: 10.0.6 '@types/node': - specifier: ^20.12.10 - version: 20.12.10 + specifier: ^20.12.11 + version: 20.12.11 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.5) @@ -134,8 +134,8 @@ devDependencies: specifier: ^1.3.1 version: 1.3.1(prettier@3.2.5) solhint: - specifier: ^4.5.4 - version: 4.5.4 + specifier: ^5.0.1 + version: 5.0.1 solhint-plugin-chainlink-solidity: specifier: git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1 version: github.com/smartcontractkit/chainlink-solhint-rules/1b4c0c2663fcd983589d4f33a2e73908624ed43c @@ -144,7 +144,7 @@ devDependencies: version: 0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.10)(typescript@5.4.5) + version: 10.9.2(@types/node@20.12.11)(typescript@5.4.5) typechain: specifier: ^8.2.1 version: 8.3.2(typescript@5.4.5) @@ -198,7 +198,7 @@ packages: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.6.1 + semver: 7.6.2 dev: false /@changesets/assemble-release-plan@5.2.4: @@ -209,7 +209,7 @@ packages: '@changesets/get-dependents-graph': 1.3.6 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 - semver: 7.6.1 + semver: 7.6.2 dev: false /@changesets/changelog-git@0.1.14: @@ -261,7 +261,7 @@ packages: p-limit: 2.3.0 preferred-pm: 3.1.3 resolve-from: 5.0.0 - semver: 7.6.1 + semver: 7.6.2 spawndamnit: 2.0.0 term-size: 2.2.1 tty-table: 4.2.3 @@ -292,7 +292,7 @@ packages: '@manypkg/get-packages': 1.1.3 chalk: 2.4.2 fs-extra: 7.0.1 - semver: 7.6.1 + semver: 7.6.2 dev: false /@changesets/get-github-info@0.5.2: @@ -1444,13 +1444,13 @@ packages: /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/cacheable-request@6.0.2: @@ -1458,14 +1458,14 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.12.10 + '@types/node': 20.12.11 '@types/responselike': 1.0.0 dev: true /@types/cbor@5.0.1: resolution: {integrity: sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/chai-as-promised@7.1.8: @@ -1505,7 +1505,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/lru-cache@5.1.1: @@ -1528,8 +1528,8 @@ packages: resolution: {integrity: sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==} dev: false - /@types/node@20.12.10: - resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==} + /@types/node@20.12.11: + resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==} dependencies: undici-types: 5.26.5 dev: true @@ -1541,7 +1541,7 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/prettier@2.7.1: @@ -1551,20 +1551,20 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 safe-buffer: 5.1.2 dev: true /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 20.12.10 + '@types/node': 20.12.11 dev: true /@types/semver@7.5.0: @@ -1592,7 +1592,7 @@ packages: graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 - semver: 7.6.1 + semver: 7.6.2 ts-api-utils: 1.0.3(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: @@ -1668,7 +1668,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.1 + semver: 7.6.2 ts-api-utils: 1.0.3(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: @@ -1688,7 +1688,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) eslint: 8.57.0 - semver: 7.6.1 + semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript @@ -1715,7 +1715,7 @@ packages: ajv: 6.12.6 better-ajv-errors: 0.8.2(ajv@6.12.6) neodoc: 2.0.2 - semver: 7.6.1 + semver: 7.6.2 source-map-support: 0.5.21 optionalDependencies: prettier: 2.8.8 @@ -3445,7 +3445,7 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.2(@types/node@20.12.10)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@20.12.11)(typescript@5.4.5) tsort: 0.0.1 typescript: 5.4.5 undici: 5.28.4 @@ -4466,7 +4466,7 @@ packages: got: 12.1.0 registry-auth-token: 5.0.2 registry-url: 6.0.1 - semver: 7.6.1 + semver: 7.6.2 dev: true /param-case@2.1.1: @@ -4600,7 +4600,7 @@ packages: dependencies: '@solidity-parser/parser': 0.17.0 prettier: 2.8.8 - semver: 7.6.1 + semver: 7.6.2 solidity-comments-extractor: 0.0.8 dev: true optional: true @@ -4613,7 +4613,7 @@ packages: dependencies: '@solidity-parser/parser': 0.17.0 prettier: 3.2.5 - semver: 7.6.1 + semver: 7.6.2 solidity-comments-extractor: 0.0.8 dev: true @@ -4917,8 +4917,8 @@ packages: hasBin: true dev: true - /semver@7.6.1: - resolution: {integrity: sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==} + /semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true @@ -5076,8 +5076,8 @@ packages: prettier-plugin-solidity: 1.3.1(prettier@3.2.5) dev: true - /solhint@4.5.4: - resolution: {integrity: sha512-Cu1XiJXub2q1eCr9kkJ9VPv1sGcmj3V7Zb76B0CoezDOB9bu3DxKIFFH7ggCl9fWpEPD6xBmRLfZrYijkVmujQ==} + /solhint@5.0.1: + resolution: {integrity: sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg==} hasBin: true dependencies: '@solidity-parser/parser': 0.18.0 @@ -5094,7 +5094,7 @@ packages: latest-version: 7.0.0 lodash: 4.17.21 pluralize: 8.0.0 - semver: 7.6.1 + semver: 7.6.2 strip-ansi: 6.0.1 table: 6.8.1 text-table: 0.2.0 @@ -5488,7 +5488,7 @@ packages: typescript: 5.4.5 dev: true - /ts-node@10.9.2(@types/node@20.12.10)(typescript@5.4.5): + /ts-node@10.9.2(@types/node@20.12.11)(typescript@5.4.5): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -5507,7 +5507,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 20.12.10 + '@types/node': 20.12.11 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol index 8d4bf17ce91..4476ac690a2 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol @@ -68,6 +68,7 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC * @member autoApproveType the auto approval setting (see enum) * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type */ + // solhint-disable-next-line gas-struct-packing struct InitialTriggerConfig { uint8 triggerType; AutoApproveType autoApproveType; diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol index 2dbc406b0e1..d2e34303df5 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol @@ -20,6 +20,7 @@ import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; * AutomationRegistry and AutomationRegistryLogic * @dev all errors, events, and internal functions should live here */ +// solhint-disable-next-line max-states-count abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.UintSet; @@ -376,6 +377,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @notice the billing config of a token * @dev this is a storage struct */ + // solhint-disable-next-line gas-struct-packing struct BillingConfig { uint32 gasFeePPB; uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167 @@ -438,6 +440,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @member gasReimbursementInJuels the amount to reimburse a node for gas spent * @member premiumInJuels the premium paid to NOPs, shared between all nodes */ + // solhint-disable-next-line gas-struct-packing struct PaymentReceipt { uint96 gasChargeInBillingToken; uint96 premiumInBillingToken; @@ -1066,6 +1069,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @notice only allows a pre-configured address to initiate offchain read */ function _preventExecution() internal view { + // solhint-disable-next-line avoid-tx-origin if (tx.origin != i_allowedReadOnlyAddress) { revert OnlySimulatedBackend(); } diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol index dbdc563d9ba..29f253f8ce3 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol @@ -95,6 +95,7 @@ contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3, Chainable { bytes memory callData = _checkPayload(id, triggerType, triggerData); gasUsed = gasleft(); + // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); gasUsed = gasUsed - gasleft(); @@ -196,6 +197,7 @@ contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3, Chainable { Upkeep memory upkeep = s_upkeep[id]; gasUsed = gasleft(); + // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); gasUsed = gasUsed - gasleft(); if (!success) { diff --git a/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol b/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol index a60e3f91543..ae920822c35 100644 --- a/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol +++ b/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface AutomationCompatibleInterface { /** * @notice method that is simulated by the keepers to see if any work actually diff --git a/contracts/src/v0.8/automation/interfaces/IAutomationV21PlusCommon.sol b/contracts/src/v0.8/automation/interfaces/IAutomationV21PlusCommon.sol index 2ce2db60e1f..6e3d0d72f79 100644 --- a/contracts/src/v0.8/automation/interfaces/IAutomationV21PlusCommon.sol +++ b/contracts/src/v0.8/automation/interfaces/IAutomationV21PlusCommon.sol @@ -141,6 +141,7 @@ interface IAutomationV21PlusCommon { * @member latestEpoch for which a report was transmitted * @member paused freeze on execution scoped to the entire registry */ + // solhint-disable-next-line gas-struct-packing struct StateLegacy { uint32 nonce; uint96 ownerLinkBalance; @@ -178,6 +179,7 @@ interface IAutomationV21PlusCommon { * @member registrars addresses of the registrar contracts * @member upkeepPrivilegeManager address which can set privilege for upkeeps */ + // solhint-disable-next-line gas-struct-packing struct OnchainConfigLegacy { uint32 paymentPremiumPPB; uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK diff --git a/contracts/src/v0.8/automation/interfaces/MigratableKeeperRegistryInterfaceV2.sol b/contracts/src/v0.8/automation/interfaces/MigratableKeeperRegistryInterfaceV2.sol index 17ca3673dc2..d6dcc03dd28 100644 --- a/contracts/src/v0.8/automation/interfaces/MigratableKeeperRegistryInterfaceV2.sol +++ b/contracts/src/v0.8/automation/interfaces/MigratableKeeperRegistryInterfaceV2.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT - pragma solidity ^0.8.0; -import "../UpkeepFormat.sol"; - +// solhint-disable-next-line interface-starts-with-i interface MigratableKeeperRegistryInterfaceV2 { /** * @notice Migrates upkeeps from one registry to another, including LINK and upkeep params. diff --git a/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol b/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol index b6ab3123f87..ed873a0ee53 100644 --- a/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol +++ b/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface StreamsLookupCompatibleInterface { error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, bytes extraData); diff --git a/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterface.sol b/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterface.sol index aa0c3c6a7f0..59d2bb4a4fa 100644 --- a/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterface.sol +++ b/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterface.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT - -import "../UpkeepFormat.sol"; - pragma solidity ^0.8.0; +import {UpkeepFormat} from "../UpkeepFormat.sol"; + +// solhint-disable-next-line interface-starts-with-i interface UpkeepTranscoderInterface { function transcodeUpkeeps( UpkeepFormat fromVersion, diff --git a/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterfaceV2.sol b/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterfaceV2.sol index e02d0f670a7..95dc3072365 100644 --- a/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterfaceV2.sol +++ b/contracts/src/v0.8/automation/interfaces/UpkeepTranscoderInterfaceV2.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT - pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface UpkeepTranscoderInterfaceV2 { function transcodeUpkeeps( uint8 fromVersion, diff --git a/contracts/src/v0.8/automation/test/StructFactory.sol b/contracts/src/v0.8/automation/test/StructFactory.sol deleted file mode 100644 index 9317244a31e..00000000000 --- a/contracts/src/v0.8/automation/test/StructFactory.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; - -contract StructFactory { - address internal OWNER; - address internal constant STRANGER = address(999); -} diff --git a/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol b/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol index 8add9568d26..f0c703679ca 100644 --- a/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol +++ b/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol @@ -60,6 +60,7 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain /** * @notice holds the variables used in the transmit function, necessary to avoid stack too deep errors */ + // solhint-disable-next-line gas-struct-packing struct TransmitVars { uint16 numUpkeepsPassedChecks; uint256 totalCalldataWeight; diff --git a/contracts/src/v0.8/automation/v2_2/AutomationRegistryBase2_2.sol b/contracts/src/v0.8/automation/v2_2/AutomationRegistryBase2_2.sol index de91cd13542..6903f55212a 100644 --- a/contracts/src/v0.8/automation/v2_2/AutomationRegistryBase2_2.sol +++ b/contracts/src/v0.8/automation/v2_2/AutomationRegistryBase2_2.sol @@ -18,6 +18,7 @@ import {IChainModule} from "../interfaces/IChainModule.sol"; * AutomationRegistry and AutomationRegistryLogic * @dev all errors, events, and internal functions should live here */ +// solhint-disable-next-line max-states-count abstract contract AutomationRegistryBase2_2 is ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.UintSet; @@ -207,6 +208,7 @@ abstract contract AutomationRegistryBase2_2 is ConfirmedOwner { * @member reorgProtectionEnabled if this registry enables re-org protection checks * @member chainModule the chain specific module */ + // solhint-disable-next-line gas-struct-packing struct OnchainConfig { uint32 paymentPremiumPPB; uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK @@ -851,6 +853,7 @@ abstract contract AutomationRegistryBase2_2 is ConfirmedOwner { * @notice only allows a pre-configured address to initiate offchain read */ function _preventExecution() internal view { + // solhint-disable-next-line avoid-tx-origin if (tx.origin != i_allowedReadOnlyAddress) { revert OnlySimulatedBackend(); } diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index 5cdb119354a..ec1ccbdda15 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -84,6 +84,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // ================================================================ // | Configuration state | // ================================================================ + // solhint-disable-next-line gas-struct-packing struct Config { uint16 maxConsumersPerSubscription; // ═════════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network diff --git a/contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol b/contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol index 68b51f89019..ac040ad47a7 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.19; contract FunctionsV1EventsMock { + // solhint-disable-next-line gas-struct-packing struct Config { uint16 maxConsumersPerSubscription; uint72 adminFee; @@ -10,6 +11,7 @@ contract FunctionsV1EventsMock { uint16 gasForCallExactCheck; uint32[] maxCallbackGasLimits; } + event ConfigUpdated(Config param1); event ContractProposed( bytes32 proposedContractSetId, diff --git a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol index 02ea5cf3721..4d159594b6d 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol @@ -84,6 +84,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { _; } + // solhint-disable-next-line gas-struct-packing struct SetConfigArgs { address[] signers; address[] transmitters; diff --git a/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol index ea1d45ffd46..5bee4360054 100644 --- a/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/v1_1_0/ocr/OCR2Base.sol @@ -76,6 +76,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { _; } + // solhint-disable-next-line gas-struct-packing struct SetConfigArgs { address[] signers; address[] transmitters; diff --git a/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol index 310107f2446..caa9c301a33 100644 --- a/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol @@ -84,6 +84,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { _; } + // solhint-disable-next-line gas-struct-packing struct SetConfigArgs { address[] signers; address[] transmitters; diff --git a/contracts/src/v0.8/interfaces/ChainlinkRequestInterface.sol b/contracts/src/v0.8/interfaces/ChainlinkRequestInterface.sol index 62e443fd6dc..5ee9cbb077d 100644 --- a/contracts/src/v0.8/interfaces/ChainlinkRequestInterface.sol +++ b/contracts/src/v0.8/interfaces/ChainlinkRequestInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface ChainlinkRequestInterface { function oracleRequest( address sender, diff --git a/contracts/src/v0.8/interfaces/ENSInterface.sol b/contracts/src/v0.8/interfaces/ENSInterface.sol index 8e7fb581d00..2592b693ad0 100644 --- a/contracts/src/v0.8/interfaces/ENSInterface.sol +++ b/contracts/src/v0.8/interfaces/ENSInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface ENSInterface { // Logged when the owner of a node assigns a new owner to a subnode. event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); diff --git a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol index f3272174ae2..6e353a79263 100644 --- a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol +++ b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol @@ -4,6 +4,7 @@ pragma abicoder v2; import {AggregatorV2V3Interface} from "../shared/interfaces/AggregatorV2V3Interface.sol"; +// solhint-disable-next-line interface-starts-with-i interface FeedRegistryInterface { struct Phase { uint16 phaseId; diff --git a/contracts/src/v0.8/interfaces/FlagsInterface.sol b/contracts/src/v0.8/interfaces/FlagsInterface.sol index 9d172c789f0..beb2b581e3f 100644 --- a/contracts/src/v0.8/interfaces/FlagsInterface.sol +++ b/contracts/src/v0.8/interfaces/FlagsInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface FlagsInterface { function getFlag(address) external view returns (bool); diff --git a/contracts/src/v0.8/interfaces/OperatorInterface.sol b/contracts/src/v0.8/interfaces/OperatorInterface.sol index 4114cce16d3..b457a50172d 100644 --- a/contracts/src/v0.8/interfaces/OperatorInterface.sol +++ b/contracts/src/v0.8/interfaces/OperatorInterface.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {OracleInterface} from "./OracleInterface.sol"; import {ChainlinkRequestInterface} from "./ChainlinkRequestInterface.sol"; +// solhint-disable-next-line interface-starts-with-i interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { function operatorRequest( address sender, diff --git a/contracts/src/v0.8/interfaces/OracleInterface.sol b/contracts/src/v0.8/interfaces/OracleInterface.sol index 40365822e10..6e7aa29e312 100644 --- a/contracts/src/v0.8/interfaces/OracleInterface.sol +++ b/contracts/src/v0.8/interfaces/OracleInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface OracleInterface { function fulfillOracleRequest( bytes32 requestId, diff --git a/contracts/src/v0.8/interfaces/PoRAddressList.sol b/contracts/src/v0.8/interfaces/PoRAddressList.sol index 717c76dbbcf..af06e29a456 100644 --- a/contracts/src/v0.8/interfaces/PoRAddressList.sol +++ b/contracts/src/v0.8/interfaces/PoRAddressList.sol @@ -9,6 +9,7 @@ pragma solidity ^0.8.0; * This makes it possible to store addresses in optimized data types and convert them to human-readable strings * in `getPoRAddressList()`. */ +// solhint-disable-next-line interface-starts-with-i interface PoRAddressList { /// @notice Get total number of addresses in the list. function getPoRAddressListLength() external view returns (uint256); diff --git a/contracts/src/v0.8/interfaces/PointerInterface.sol b/contracts/src/v0.8/interfaces/PointerInterface.sol index ca2b82af56a..ca0b1de8f74 100644 --- a/contracts/src/v0.8/interfaces/PointerInterface.sol +++ b/contracts/src/v0.8/interfaces/PointerInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface PointerInterface { function getAddress() external view returns (address); } diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol index 6943b9fbb91..57b507bae8d 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface ArbitrumSequencerUptimeFeedInterface { function updateStatus(bool status, uint64 timestamp) external; } diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol index a4cc6a9f451..ddcfded9ca2 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; /// @title CrossDomainOwnableInterface - A contract with helpers for cross-domain contract ownership +// solhint-disable-next-line interface-starts-with-i interface CrossDomainOwnableInterface { event L1OwnershipTransferRequested(address indexed from, address indexed to); diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol index 792e83edc5d..498dee586c8 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; /// @title DelegateForwarderInterface - forwards a delegatecall to a target, under some conditions +// solhint-disable-next-line interface-starts-with-i interface DelegateForwarderInterface { /** * @notice forward delegatecalls the `target` with `data` diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol index b5fd70bd8c4..b6491a9d601 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; +// solhint-disable-next-line interface-starts-with-i interface FlagsInterface { function getFlag(address) external view returns (bool); diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol index a3c29e5f786..a6db32b9231 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; /// @title ForwarderInterface - forwards a call to a target, under some conditions +// solhint-disable-next-line interface-starts-with-i interface ForwarderInterface { /** * @notice forward calls the `target` with `data` diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol index 281966b7999..a08a1b26204 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface OptimismSequencerUptimeFeedInterface { function updateStatus(bool status, uint64 timestamp) external; } diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol index f0f716d6f02..89327fbc3a1 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.19; +// solhint-disable-next-line interface-starts-with-i interface ScrollSequencerUptimeFeedInterface { function updateStatus(bool status, uint64 timestamp) external; } diff --git a/contracts/src/v0.8/llo-feeds/dev/ChannelConfigStore.sol b/contracts/src/v0.8/llo-feeds/dev/ChannelConfigStore.sol index ca24b775398..6c6a5ec9b3e 100644 --- a/contracts/src/v0.8/llo-feeds/dev/ChannelConfigStore.sol +++ b/contracts/src/v0.8/llo-feeds/dev/ChannelConfigStore.sol @@ -87,6 +87,7 @@ contract ChannelConfigStore is ConfirmedOwner, IChannelConfigStore, TypeAndVersi } function getChannelDefinitions(uint32 channelId) external view returns (ChannelDefinition memory) { + // solhint-disable-next-line avoid-tx-origin if (msg.sender != tx.origin) { revert OnlyCallableByEOA(); } diff --git a/contracts/src/v0.8/operatorforwarder/test/testhelpers/Callback.sol b/contracts/src/v0.8/operatorforwarder/test/testhelpers/Callback.sol index 9dccfed428a..3d725714c02 100644 --- a/contracts/src/v0.8/operatorforwarder/test/testhelpers/Callback.sol +++ b/contracts/src/v0.8/operatorforwarder/test/testhelpers/Callback.sol @@ -11,6 +11,7 @@ contract Callback { // Callback function for oracle request fulfillment function callback(bytes32) public { + // solhint-disable-next-line gas-custom-errors require(msg.sender == s_operator, "Only Operator can call this function"); s_callbacksReceived += 1; } diff --git a/contracts/src/v0.8/operatorforwarder/test/testhelpers/Consumer.sol b/contracts/src/v0.8/operatorforwarder/test/testhelpers/Consumer.sol index 82709d3def8..3ec32dd6a29 100644 --- a/contracts/src/v0.8/operatorforwarder/test/testhelpers/Consumer.sol +++ b/contracts/src/v0.8/operatorforwarder/test/testhelpers/Consumer.sol @@ -41,6 +41,7 @@ contract Consumer is ChainlinkClient { function withdrawLink() public { LinkTokenInterface _link = LinkTokenInterface(_chainlinkTokenAddress()); + // solhint-disable-next-line gas-custom-errors require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); } diff --git a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MaliciousMultiWordConsumer.sol b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MaliciousMultiWordConsumer.sol index d9d14cb3d43..6e5881524f5 100644 --- a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MaliciousMultiWordConsumer.sol +++ b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MaliciousMultiWordConsumer.sol @@ -35,12 +35,14 @@ contract MaliciousMultiWordConsumer is ChainlinkClient { function stealEthCall(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { (bool success, ) = address(this).call{value: 100}(""); // solhint-disable-line avoid-call-value + // solhint-disable-next-line gas-custom-errors require(success, "Call failed"); } function stealEthSend(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { // solhint-disable-next-line check-send-result bool success = payable(address(this)).send(100); // solhint-disable-line multiple-sends + // solhint-disable-next-line gas-custom-errors require(success, "Send failed"); } diff --git a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MockReceiver.sol b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MockReceiver.sol index 4e825b4505f..38a0c3d9269 100644 --- a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MockReceiver.sol +++ b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MockReceiver.sol @@ -9,6 +9,7 @@ contract MockReceiver { } function revertMessage() public pure { + // solhint-disable-next-line gas-custom-errors revert("test revert message"); } diff --git a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MultiWordConsumer.sol b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MultiWordConsumer.sol index fe249831fef..b3fdfcb813a 100644 --- a/contracts/src/v0.8/operatorforwarder/test/testhelpers/MultiWordConsumer.sol +++ b/contracts/src/v0.8/operatorforwarder/test/testhelpers/MultiWordConsumer.sol @@ -86,6 +86,7 @@ contract MultiWordConsumer is ChainlinkClient { function withdrawLink() public { LinkTokenInterface _link = LinkTokenInterface(_chainlinkTokenAddress()); + // solhint-disable-next-line gas-custom-errors require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); } diff --git a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol index 7884d4814f2..7a90f2abf93 100644 --- a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol @@ -79,6 +79,7 @@ abstract contract OCR2Base is OwnerIsCreator, OCR2Abstract { _; } + // solhint-disable-next-line gas-struct-packing struct SetConfigArgs { address[] signers; address[] transmitters; diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol index 2cc0c44c451..32969acad70 100644 --- a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol +++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line gas-struct-packing struct TestStruct { int32 Field; string DifferentField; diff --git a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol index 1cbf2aa0093..cf29f148a54 100644 --- a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol @@ -80,6 +80,7 @@ contract BatchBlockhashStore { } } +// solhint-disable-next-line interface-starts-with-i interface BlockhashStore { function storeVerifyHeader(uint256 n, bytes memory header) external; diff --git a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol index 2cb6948a9e3..b9230f66ee9 100644 --- a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol @@ -59,6 +59,7 @@ contract BatchVRFCoordinatorV2 { } } +// solhint-disable-next-line interface-starts-with-i interface VRFCoordinatorV2 { function fulfillRandomWords( VRFTypes.Proof memory proof, diff --git a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol index ae0e3cc8206..a656ef071f1 100644 --- a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol +++ b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol @@ -419,6 +419,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas } } +// solhint-disable-next-line interface-starts-with-i interface ExtendedVRFCoordinatorV2Interface is VRFCoordinatorV2Interface { function getConfig() external diff --git a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol index c070c7d1e17..bde8267e30f 100644 --- a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol @@ -691,6 +691,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { error CoordinatorAlreadyRegistered(address coordinatorAddress); /// @dev encapsulates data to be migrated from current coordinator + // solhint-disable-next-line gas-struct-packing struct V1MigrationData { uint8 fromVersion; uint256 subId; diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index c88d7dec397..53f499305e5 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -685,6 +685,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is error CoordinatorAlreadyRegistered(address coordinatorAddress); /// @dev encapsulates data to be migrated from current coordinator + // solhint-disable-next-line gas-struct-packing struct V1MigrationData { uint8 fromVersion; uint256 subId; diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol index 0204be807f5..1a2ed50e6f0 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol @@ -78,6 +78,7 @@ contract VRFCoordinatorV2Plus_V2Example is IVRFCoordinatorV2PlusMigration { error InvalidNativeBalance(uint256 transferredValue, uint96 expectedValue); /// @dev encapsulates data migrated over from previous coordinator + // solhint-disable-next-line gas-struct-packing struct V1MigrationData { uint8 fromVersion; uint256 subId; diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol index 4d8b6de4a43..2ae45db9c48 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol @@ -11,6 +11,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore LinkTokenInterface internal LINKTOKEN; + // solhint-disable-next-line gas-struct-packing struct RequestConfig { uint256 subId; uint32 callbackGasLimit; diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol index 62e6ed2da1e..9510b1ba0ea 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol @@ -9,6 +9,7 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); event WrapperRequestMade(uint256 indexed requestId, uint256 paid); + // solhint-disable-next-line gas-struct-packing struct RequestStatus { uint256 paid; bool fulfilled; diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol index 1389aee5f37..c4c968e5a18 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol @@ -20,6 +20,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); event WrapperRequestMade(uint256 indexed requestId, uint256 paid); + // solhint-disable-next-line gas-struct-packing struct RequestStatus { uint256 paid; bool fulfilled; diff --git a/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol b/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol index 81775570cef..6a42b5b9644 100644 --- a/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol +++ b/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface BlockhashStoreInterface { function getBlockhash(uint256 number) external view returns (bytes32); } diff --git a/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol b/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol index fdb76dc6661..3cb9934d5c7 100644 --- a/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol +++ b/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface VRFCoordinatorV2Interface { /** * @notice Get configuration relevant for making requests diff --git a/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol b/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol index 71dbfb6b478..daac1586681 100644 --- a/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol +++ b/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +// solhint-disable-next-line interface-starts-with-i interface VRFV2WrapperInterface { /** * @return the request ID of the most recent VRF V2 request made by this wrapper. This should only From 1b1e31ebfc5198ab7e43291110b6f5d54e467a01 Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Wed, 15 May 2024 16:08:34 -0400 Subject: [PATCH 12/17] Fix automation test (#13213) * fix automation test flake * add changeset * update * udpate * fix lint * update --- .changeset/hungry-apes-hope.md | 6 ++++++ integration-tests/smoke/automation_test.go | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 .changeset/hungry-apes-hope.md diff --git a/.changeset/hungry-apes-hope.md b/.changeset/hungry-apes-hope.md new file mode 100644 index 00000000000..db2275694ca --- /dev/null +++ b/.changeset/hungry-apes-hope.md @@ -0,0 +1,6 @@ +--- +"chainlink": patch +--- + +#bugfix +fix an automation smoke test flake diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 1025ed48a0b..2c5295326bc 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -1262,9 +1262,10 @@ func TestSetOffchainConfigWithMaxGasPrice(t *testing.T) { for i := 0; i < len(upkeepIDs); i++ { latestCounter, err = consumers[i].Counter(testcontext.Get(t)) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) - g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterSettingLowMaxGasPrice[i].Int64()), - "Expected consumer counter to remain constant at %d, but got %d", - countersAfterSettingLowMaxGasPrice[i].Int64(), latestCounter.Int64()) + g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSettingLowMaxGasPrice[i].Int64()+1), + "Expected consumer counter to be less than %d, but got %d", + countersAfterSettingLowMaxGasPrice[i].Int64()+1, latestCounter.Int64()) + } }, "2m", "5s").Should(gomega.Succeed()) l.Info().Msg("no upkeeps is performed because their max gas price is only 1 wei") From 0917394a4625c3e97b17e348dd473199a15402bf Mon Sep 17 00:00:00 2001 From: Finley Decker Date: Wed, 15 May 2024 11:30:33 -1000 Subject: [PATCH 13/17] update bumpThresholds for chains using suggestedPrice estimator (#13078) * update bumpThresholds for chains using suggestedPrice estimator * added changeset * added changeset * added tag to changeset * updated config docs --------- Co-authored-by: Prashant Yadav <34992934+prashantkumar1982@users.noreply.github.com> --- .changeset/silver-birds-wave.md | 5 +++++ .../config/toml/defaults/Arbitrum_Goerli.toml | 3 +-- .../toml/defaults/Arbitrum_Mainnet.toml | 3 +-- .../toml/defaults/Arbitrum_Rinkeby.toml | 3 +-- .../toml/defaults/Arbitrum_Sepolia.toml | 3 +-- .../config/toml/defaults/Klaytn_Mainnet.toml | 2 +- .../config/toml/defaults/Klaytn_Testnet.toml | 2 +- .../config/toml/defaults/Metis_Mainnet.toml | 3 +-- .../config/toml/defaults/Metis_Rinkeby.toml | 2 +- .../config/toml/defaults/Metis_Sepolia.toml | 2 +- .../config/toml/defaults/Scroll_Mainnet.toml | 2 -- .../config/toml/defaults/Scroll_Sepolia.toml | 2 -- docs/CONFIG.md | 22 +++++++++---------- 13 files changed, 25 insertions(+), 29 deletions(-) create mode 100644 .changeset/silver-birds-wave.md diff --git a/.changeset/silver-birds-wave.md b/.changeset/silver-birds-wave.md new file mode 100644 index 00000000000..e5a98dcde20 --- /dev/null +++ b/.changeset/silver-birds-wave.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +bumpThreshold config setting for chains using suggestPrice estimator #updated diff --git a/core/chains/evm/config/toml/defaults/Arbitrum_Goerli.toml b/core/chains/evm/config/toml/defaults/Arbitrum_Goerli.toml index 598b571352d..42de6beb9ba 100644 --- a/core/chains/evm/config/toml/defaults/Arbitrum_Goerli.toml +++ b/core/chains/evm/config/toml/defaults/Arbitrum_Goerli.toml @@ -13,8 +13,7 @@ PriceMin = '0' PriceDefault = '0.1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' FeeCapDefault = '1000 gwei' -# Disable gas bumping on arbitrum -BumpThreshold = 0 +BumpThreshold = 5 [GasEstimator.BlockHistory] # Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum diff --git a/core/chains/evm/config/toml/defaults/Arbitrum_Mainnet.toml b/core/chains/evm/config/toml/defaults/Arbitrum_Mainnet.toml index 350d15cfccb..b297db1bc0f 100644 --- a/core/chains/evm/config/toml/defaults/Arbitrum_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Arbitrum_Mainnet.toml @@ -15,8 +15,7 @@ PriceMin = '0' PriceDefault = '0.1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' FeeCapDefault = '1000 gwei' -# Disable gas bumping on arbitrum -BumpThreshold = 0 +BumpThreshold = 5 [GasEstimator.BlockHistory] # Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum diff --git a/core/chains/evm/config/toml/defaults/Arbitrum_Rinkeby.toml b/core/chains/evm/config/toml/defaults/Arbitrum_Rinkeby.toml index ef9a5408a53..f9296adcb76 100644 --- a/core/chains/evm/config/toml/defaults/Arbitrum_Rinkeby.toml +++ b/core/chains/evm/config/toml/defaults/Arbitrum_Rinkeby.toml @@ -13,8 +13,7 @@ PriceMin = '0' PriceDefault = '0.1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' FeeCapDefault = '1000 gwei' -# Disable gas bumping on arbitrum -BumpThreshold = 0 +BumpThreshold = 5 [GasEstimator.BlockHistory] # Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum diff --git a/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml b/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml index e26a137d2ba..e6d660a2729 100644 --- a/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml @@ -12,8 +12,7 @@ PriceMin = '0' PriceDefault = '0.1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' FeeCapDefault = '1000 gwei' -# Disable gas bumping on arbitrum -BumpThreshold = 0 +BumpThreshold = 5 [GasEstimator.BlockHistory] # Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum diff --git a/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml b/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml index c68f03b0446..1994f309afc 100644 --- a/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Klaytn_Mainnet.toml @@ -7,4 +7,4 @@ OCR.ContractConfirmations = 1 [GasEstimator] Mode = 'SuggestedPrice' PriceDefault = '750 gwei' # gwei = ston -BumpThreshold = 0 +BumpThreshold = 5 diff --git a/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml b/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml index 864aa0fa72a..625afd649ea 100644 --- a/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml +++ b/core/chains/evm/config/toml/defaults/Klaytn_Testnet.toml @@ -7,4 +7,4 @@ OCR.ContractConfirmations = 1 [GasEstimator] Mode = 'SuggestedPrice' PriceDefault = '750 gwei' # gwei = ston -BumpThreshold = 0 +BumpThreshold = 5 diff --git a/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml b/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml index 3e8efa531cc..337138d565e 100644 --- a/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Metis_Mainnet.toml @@ -11,8 +11,7 @@ OCR.ContractConfirmations = 1 Mode = 'SuggestedPrice' # Metis uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' -# Never bump gas on metis -BumpThreshold = 0 +BumpThreshold = 3 [BalanceMonitor] Enabled = true diff --git a/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml b/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml index 7d9fec9076f..5dccf3719b9 100644 --- a/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml +++ b/core/chains/evm/config/toml/defaults/Metis_Rinkeby.toml @@ -11,7 +11,7 @@ Enabled = true [GasEstimator] Mode = 'SuggestedPrice' PriceMin = '0' -BumpThreshold = 0 +BumpThreshold = 3 [GasEstimator.BlockHistory] BlockHistorySize = 0 diff --git a/core/chains/evm/config/toml/defaults/Metis_Sepolia.toml b/core/chains/evm/config/toml/defaults/Metis_Sepolia.toml index 2391ee2cab3..d8ddffd77d7 100644 --- a/core/chains/evm/config/toml/defaults/Metis_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Metis_Sepolia.toml @@ -11,7 +11,7 @@ Enabled = true [GasEstimator] Mode = 'SuggestedPrice' PriceMin = '0' -BumpThreshold = 0 +BumpThreshold = 3 [GasEstimator.BlockHistory] BlockHistorySize = 0 diff --git a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml index e087b86fe3e..21d4699ee8a 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml @@ -11,8 +11,6 @@ OCR.ContractConfirmations = 1 Mode = 'SuggestedPrice' # Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' -# Never bump gas on Scroll -BumpThreshold = 0 [GasEstimator.BlockHistory] # Force an error if someone enables the estimator by accident; we never want to run the block history estimator on Scroll diff --git a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml index 9db7a8ebed5..27ac984865d 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml @@ -11,8 +11,6 @@ OCR.ContractConfirmations = 1 Mode = 'SuggestedPrice' # Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price PriceMin = '0' -# Never bump gas on Scroll -BumpThreshold = 0 [GasEstimator.BlockHistory] # Force an error if someone enables the estimator by accident; we never want to run the block history estimator on Scroll diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 61ba9256d9d..a0e2957cd72 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -3729,7 +3729,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 3 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -3813,7 +3813,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -3898,7 +3898,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 3 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -4658,7 +4658,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -4914,7 +4914,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '1 micro' TipCapDefault = '1 wei' @@ -5591,7 +5591,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 3 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -6016,7 +6016,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '1 micro' TipCapDefault = '1 wei' @@ -6102,7 +6102,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '1 micro' TipCapDefault = '1 wei' @@ -6187,7 +6187,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 5 EIP1559DynamicFees = false FeeCapDefault = '1 micro' TipCapDefault = '1 wei' @@ -6272,7 +6272,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 3 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' @@ -6357,7 +6357,7 @@ LimitMultiplier = '1' LimitTransfer = 21000 BumpMin = '5 gwei' BumpPercent = 20 -BumpThreshold = 0 +BumpThreshold = 3 EIP1559DynamicFees = false FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' From aeb9f4d50d6513c6b2be46e19b36b12a5de22738 Mon Sep 17 00:00:00 2001 From: krehermann Date: Wed, 15 May 2024 16:54:56 -0600 Subject: [PATCH 14/17] Decouple static workflow graph validation from execution state (#13201) * Decouple static workflow graph validation from execution state * linter; revert executable to step; fix preexisiting shadowing in engine * address feedback --- core/services/workflows/engine.go | 40 +++---- core/services/workflows/models.go | 142 ++++++++++++++++++++----- core/services/workflows/models_yaml.go | 18 ++-- 3 files changed, 143 insertions(+), 57 deletions(-) diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 292ad9c6468..2b497057ada 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -122,37 +122,37 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { return capabilityRegistrationErr } -func (e *Engine) initializeCapability(ctx context.Context, s *step) error { +func (e *Engine) initializeCapability(ctx context.Context, step *step) error { // If the capability already exists, that means we've already registered it - if s.capability != nil { + if step.capability != nil { return nil } - cp, err := e.registry.Get(ctx, s.ID) + cp, err := e.registry.Get(ctx, step.ID) if err != nil { - return fmt.Errorf("failed to get capability with ref %s: %s", s.ID, err) + return fmt.Errorf("failed to get capability with ref %s: %s", step.ID, err) } // We configure actions, consensus and targets here, and // they all satisfy the `CallbackCapability` interface cc, ok := cp.(capabilities.CallbackCapability) if !ok { - return fmt.Errorf("could not coerce capability %s to CallbackCapability", s.ID) + return fmt.Errorf("could not coerce capability %s to CallbackCapability", step.ID) } - if s.config == nil { - configMap, newMapErr := values.NewMap(s.Config) + if step.config == nil { + configMap, newMapErr := values.NewMap(step.Config) if newMapErr != nil { return fmt.Errorf("failed to convert config to values.Map: %s", newMapErr) } - s.config = configMap + step.config = configMap } registrationRequest := capabilities.RegisterToWorkflowRequest{ Metadata: capabilities.RegistrationMetadata{ WorkflowID: e.workflow.id, }, - Config: s.config, + Config: step.config, } err = cc.RegisterToWorkflow(ctx, registrationRequest) @@ -160,7 +160,7 @@ func (e *Engine) initializeCapability(ctx context.Context, s *step) error { return fmt.Errorf("failed to register to workflow (%+v): %w", registrationRequest, err) } - s.capability = cc + step.capability = cc return nil } @@ -260,8 +260,8 @@ func (e *Engine) resumeInProgressExecutions(ctx context.Context) error { // and `scheduledExecution` for targets. If we don't have the necessary // config to initialize a scheduledExecution for a target, we'll fallback to // using `immediateExecution`. -func (e *Engine) initializeExecutionStrategy(step *step) error { - if step.executionStrategy != nil { +func (e *Engine) initializeExecutionStrategy(s *step) error { + if s.executionStrategy != nil { return nil } @@ -272,16 +272,16 @@ func (e *Engine) initializeExecutionStrategy(step *step) error { } ie := immediateExecution{} - if step.CapabilityType != capabilities.CapabilityTypeTarget { - e.logger.Debugf("initializing step %+v with immediate execution strategy: not a target", step) - step.executionStrategy = ie + if s.CapabilityType != capabilities.CapabilityTypeTarget { + e.logger.Debugf("initializing step %+v with immediate execution strategy: not a target", s) + s.executionStrategy = ie return nil } dinfo := e.donInfo if dinfo.DON == nil { e.logger.Debugf("initializing target step with immediate execution strategy: donInfo %+v", e.donInfo) - step.executionStrategy = ie + s.executionStrategy = ie return nil } @@ -294,17 +294,17 @@ func (e *Engine) initializeExecutionStrategy(step *step) error { } if position == nil { - e.logger.Debugf("initializing step %+v with immediate execution strategy: position not found in donInfo %+v", step, e.donInfo) - step.executionStrategy = ie + e.logger.Debugf("initializing step %+v with immediate execution strategy: position not found in donInfo %+v", s, e.donInfo) + s.executionStrategy = ie return nil } - step.executionStrategy = scheduledExecution{ + s.executionStrategy = scheduledExecution{ DON: e.donInfo.DON, Position: *position, PeerID: e.donInfo.PeerID(), } - e.logger.Debugf("initializing step %+v with scheduled execution strategy", step) + e.logger.Debugf("initializing step %+v with scheduled execution strategy", s) return nil } diff --git a/core/services/workflows/models.go b/core/services/workflows/models.go index 8dce11cabe5..dadadc8ba0e 100644 --- a/core/services/workflows/models.go +++ b/core/services/workflows/models.go @@ -16,10 +16,10 @@ type stepRequest struct { state store.WorkflowExecution } -// stepDefinition is the parsed representation of a step in a workflow. +// StepDefinition is the parsed representation of a step in a workflow. // // Within the workflow spec, they are called "Capability Properties". -type stepDefinition struct { +type StepDefinition struct { ID string `json:"id" jsonschema:"required"` Ref string `json:"ref,omitempty" jsonschema:"pattern=^[a-z0-9_]+$"` Inputs map[string]any `json:"inputs,omitempty"` @@ -28,16 +28,16 @@ type stepDefinition struct { CapabilityType capabilities.CapabilityType `json:"-"` } -// workflowSpec is the parsed representation of a workflow. -type workflowSpec struct { - Triggers []stepDefinition `json:"triggers" jsonschema:"required"` - Actions []stepDefinition `json:"actions,omitempty"` - Consensus []stepDefinition `json:"consensus" jsonschema:"required"` - Targets []stepDefinition `json:"targets" jsonschema:"required"` +// WorkflowSpec is the parsed representation of a workflow. +type WorkflowSpec struct { + Triggers []StepDefinition `json:"triggers" jsonschema:"required"` + Actions []StepDefinition `json:"actions,omitempty"` + Consensus []StepDefinition `json:"consensus" jsonschema:"required"` + Targets []StepDefinition `json:"targets" jsonschema:"required"` } -func (w *workflowSpec) steps() []stepDefinition { - s := []stepDefinition{} +func (w *WorkflowSpec) Steps() []StepDefinition { + s := []StepDefinition{} s = append(s, w.Actions...) s = append(s, w.Consensus...) s = append(s, w.Targets...) @@ -55,7 +55,7 @@ type workflow struct { triggers []*triggerCapability - spec *workflowSpec + spec *WorkflowSpec } func (w *workflow) walkDo(start string, do func(s *step) error) error { @@ -106,17 +106,39 @@ func (w *workflow) dependents(start string) ([]*step, error) { return steps, nil } -// step wraps a stepDefinition with additional context for dependencies and execution +// step wraps a Vertex with additional context for execution that is mutated by the engine type step struct { - stepDefinition - dependencies []string + Vertex capability capabilities.CallbackCapability config *values.Map executionStrategy executionStrategy } +type Vertex struct { + StepDefinition + dependencies []string +} + +// DependencyGraph is an intermediate representation of a workflow wherein all the graph +// vertices are represented and validated. It is a static representation of the workflow dependencies. +type DependencyGraph struct { + ID string + graph.Graph[string, *Vertex] + + Triggers []*StepDefinition + + Spec *WorkflowSpec +} + +// VID is an identifier for a Vertex that can be used to uniquely identify it in a graph. +// it represents the notion `hash` in the graph package AddVertex method. +// we refrain from naming it `hash` to avoid confusion with the hash function. +func (v *Vertex) VID() string { + return v.Ref +} + type triggerCapability struct { - stepDefinition + StepDefinition trigger capabilities.TriggerCapability config *values.Map } @@ -126,6 +148,14 @@ const ( ) func Parse(yamlWorkflow string) (*workflow, error) { + wf2, err := ParseDepedencyGraph(yamlWorkflow) + if err != nil { + return nil, err + } + return createWorkflow(wf2) +} + +func ParseDepedencyGraph(yamlWorkflow string) (*DependencyGraph, error) { spec, err := ParseWorkflowSpecYaml(yamlWorkflow) if err != nil { return nil, err @@ -138,23 +168,23 @@ func Parse(yamlWorkflow string) (*workflow, error) { // Note: all triggers are represented by a single step called // `trigger`. This is because for workflows with multiple triggers // only one trigger will have started the workflow. - stepHash := func(s *step) string { - return s.Ref + stepHash := func(s *Vertex) string { + return s.VID() } g := graph.New( stepHash, graph.PreventCycles(), graph.Directed(), ) - err = g.AddVertex(&step{ - stepDefinition: stepDefinition{Ref: keywordTrigger}, + err = g.AddVertex(&Vertex{ + StepDefinition: StepDefinition{Ref: keywordTrigger}, }) if err != nil { return nil, err } // Next, let's populate the other entries in the graph. - for _, s := range spec.steps() { + for _, s := range spec.Steps() { // TODO: The workflow format spec doesn't always require a `Ref` // to be provided (triggers and targets don't have a `Ref` for example). // To handle this, we default the `Ref` to the type, but ideally we @@ -163,7 +193,7 @@ func Parse(yamlWorkflow string) (*workflow, error) { s.Ref = s.ID } - innerErr := g.AddVertex(&step{stepDefinition: s}) + innerErr := g.AddVertex(&Vertex{StepDefinition: s}) if innerErr != nil { return nil, fmt.Errorf("cannot add vertex %s: %w", s.Ref, innerErr) } @@ -200,16 +230,72 @@ func Parse(yamlWorkflow string) (*workflow, error) { } } - triggerSteps := []*triggerCapability{} + triggerSteps := []*StepDefinition{} for _, t := range spec.Triggers { - triggerSteps = append(triggerSteps, &triggerCapability{ - stepDefinition: t, - }) + tt := t + triggerSteps = append(triggerSteps, &tt) } - wf := &workflow{ - spec: &spec, + wf := &DependencyGraph{ + Spec: &spec, Graph: g, - triggers: triggerSteps, + Triggers: triggerSteps, } return wf, err } + +// createWorkflow converts a StaticWorkflow to an executable workflow +// by adding metadata to the vertices that is owned by the workflow runtime. +func createWorkflow(wf2 *DependencyGraph) (*workflow, error) { + out := &workflow{ + id: wf2.ID, + triggers: []*triggerCapability{}, + spec: wf2.Spec, + } + + for _, t := range wf2.Triggers { + out.triggers = append(out.triggers, &triggerCapability{ + StepDefinition: *t, + }) + } + + stepHash := func(s *step) string { + // must use the same hash function as the DependencyGraph. + // this ensures that the intermediate representation (DependencyGraph) and the workflow + // representation label vertices with the same identifier, which in turn allows us to + // to copy the edges from the intermediate representation to the executable representation. + return s.Vertex.VID() + } + g := graph.New( + stepHash, + graph.PreventCycles(), + graph.Directed(), + ) + adjMap, err := wf2.Graph.AdjacencyMap() + if err != nil { + return nil, fmt.Errorf("failed to convert intermediate representation to adjacency map: %w", err) + } + + // copy the all the vertices from the intermediate graph to the executable workflow graph + for vertexRef := range adjMap { + v, innerErr := wf2.Graph.Vertex(vertexRef) + if innerErr != nil { + return nil, fmt.Errorf("failed to retrieve vertex for %s: %w", vertexRef, innerErr) + } + innerErr = g.AddVertex(&step{Vertex: *v}) + if innerErr != nil { + return nil, fmt.Errorf("failed to add vertex to executable workflow %s: %w", vertexRef, innerErr) + } + } + // now we can add all the edges. this works because we are using vertex hash function is the same in both graphs. + // see comment on `stepHash` function. + for vertexRef, edgeRefs := range adjMap { + for edgeRef := range edgeRefs { + innerErr := g.AddEdge(vertexRef, edgeRef) + if innerErr != nil { + return nil, fmt.Errorf("failed to add edge from '%s' to '%s': %w", vertexRef, edgeRef, innerErr) + } + } + } + out.Graph = g + return out, nil +} diff --git a/core/services/workflows/models_yaml.go b/core/services/workflows/models_yaml.go index 74ed8ee466d..90d3f109c06 100644 --- a/core/services/workflows/models_yaml.go +++ b/core/services/workflows/models_yaml.go @@ -20,7 +20,7 @@ func GenerateJsonSchema() ([]byte, error) { return json.MarshalIndent(schema, "", " ") } -func ParseWorkflowSpecYaml(data string) (workflowSpec, error) { +func ParseWorkflowSpecYaml(data string) (WorkflowSpec, error) { w := workflowSpecYaml{} err := yaml.Unmarshal([]byte(data), &w) @@ -46,36 +46,36 @@ type workflowSpecYaml struct { // // We support multiple ways of defining a workflow spec yaml, // but internally we want to work with a single representation. -func (w workflowSpecYaml) toWorkflowSpec() workflowSpec { - triggers := make([]stepDefinition, 0, len(w.Triggers)) +func (w workflowSpecYaml) toWorkflowSpec() WorkflowSpec { + triggers := make([]StepDefinition, 0, len(w.Triggers)) for _, t := range w.Triggers { sd := t.toStepDefinition() sd.CapabilityType = capabilities.CapabilityTypeTrigger triggers = append(triggers, sd) } - actions := make([]stepDefinition, 0, len(w.Actions)) + actions := make([]StepDefinition, 0, len(w.Actions)) for _, a := range w.Actions { sd := a.toStepDefinition() sd.CapabilityType = capabilities.CapabilityTypeAction actions = append(actions, sd) } - consensus := make([]stepDefinition, 0, len(w.Consensus)) + consensus := make([]StepDefinition, 0, len(w.Consensus)) for _, c := range w.Consensus { sd := c.toStepDefinition() sd.CapabilityType = capabilities.CapabilityTypeConsensus consensus = append(consensus, sd) } - targets := make([]stepDefinition, 0, len(w.Targets)) + targets := make([]StepDefinition, 0, len(w.Targets)) for _, t := range w.Targets { sd := t.toStepDefinition() sd.CapabilityType = capabilities.CapabilityTypeTarget targets = append(targets, sd) } - return workflowSpec{ + return WorkflowSpec{ Triggers: triggers, Actions: actions, Consensus: consensus, @@ -247,8 +247,8 @@ type stepDefinitionYaml struct { // toStepDefinition converts a stepDefinitionYaml to a stepDefinition. // // `stepDefinition` is the converged representation of a step in a workflow. -func (s stepDefinitionYaml) toStepDefinition() stepDefinition { - return stepDefinition{ +func (s stepDefinitionYaml) toStepDefinition() StepDefinition { + return StepDefinition{ Ref: s.Ref, ID: s.ID.String(), Inputs: s.Inputs, From 7be350606d009a38cffdf95f9b424a5f64d06157 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Thu, 16 May 2024 09:58:17 +0200 Subject: [PATCH 15/17] Use Seth EVM client in E2E VRF tests (#12964) * WIP: smoke/vrfv2_test.go * wip 2 * wip 3 * wip 4 * wip 5 * wip 6 * wip 7 * wip 8 * fix * wip 9 * wip 10 * fix * fix go mod * fix * fix lint * fix * Fix * fix vrfv2plus * fix 2 * fix * wip * bump gas limit for sending funds to EOA * check receipt when sending funds * fix go mod * Fix test context * use latest Seth that estimates gas for funds sending * adding Polygon Amoy and Arb Sepolia with default config; small refactoring * Fix passing wrapped contract backend * Use MustGetRootKeyAddress() * Show funding amount in ETH * Remove legacy vrf code * Fix lint * Fix lint 2 * Use AnySyncedKey in wasp guns * Log key num * Add RequestRandomnessFromKey and use GetChainClientWithConfigFunction in load tests * Extract events from tx logs * Use SethRootKeyIndex * Fix getting event data * Fix parsing events * Fix load tests * Do not use AnySyncedKey * Support multiple keys with AvailableSethKeyNum --------- Co-authored-by: Bartek Tofel Co-authored-by: Ilja Pavlovs --- integration-tests/actions/actions.go | 67 +- .../actions/ocr2vrf_actions/ocr2vrf_steps.go | 58 +- integration-tests/actions/seth/actions.go | 23 +- .../actions/vrf/common/actions.go | 43 +- .../actions/vrf/common/logging_helpers.go | 4 + .../actions/vrf/vrfv2/contract_steps.go | 200 +--- .../actions/vrf/vrfv2/logging_helpers.go | 2 + .../actions/vrf/vrfv2/setup_steps.go | 78 +- .../actions/vrf/vrfv2plus/contract_steps.go | 150 +-- .../actions/vrf/vrfv2plus/logging_helpers.go | 5 +- .../actions/vrf/vrfv2plus/setup_steps.go | 105 +- integration-tests/chaos/ocr2vrf_chaos_test.go | 24 +- .../contracts/contract_deployer.go | 83 +- .../contracts/contract_loader.go | 93 +- .../contracts/contract_vrf_models.go | 44 +- .../contracts/ethereum_contracts.go | 3 - .../contracts/ethereum_contracts_seth.go | 5 +- .../contracts/ethereum_ocr2vrf_contracts.go | 381 ++++---- .../contracts/ethereum_vrf_common.go | 17 - .../contracts/ethereum_vrf_contracts.go | 527 ++++++---- .../contracts/ethereum_vrf_contracts_seth.go | 247 ----- .../contracts/ethereum_vrfv2_contracts.go | 911 ++++++++---------- .../contracts/ethereum_vrfv2plus_contracts.go | 729 ++++++-------- integration-tests/docker/test_env/test_env.go | 6 + .../docker/test_env/test_env_builder.go | 4 +- integration-tests/load/vrfv2/gun.go | 10 + integration-tests/load/vrfv2/vrfv2_test.go | 56 +- integration-tests/load/vrfv2plus/gun.go | 10 + .../load/vrfv2plus/vrfv2plus_test.go | 65 +- integration-tests/smoke/ocr2vrf_test.go | 45 +- integration-tests/smoke/vrfv2_test.go | 237 +++-- integration-tests/smoke/vrfv2plus_test.go | 387 ++++---- integration-tests/testconfig/default.toml | 57 +- integration-tests/utils/seth.go | 12 + 34 files changed, 2041 insertions(+), 2647 deletions(-) delete mode 100644 integration-tests/contracts/ethereum_vrf_contracts_seth.go diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index ee4309c3613..d666a497666 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -28,6 +28,8 @@ import ( "github.com/rs/zerolog/log" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" @@ -474,36 +476,12 @@ func GenerateWallet() (common.Address, error) { return crypto.PubkeyToAddress(*publicKeyECDSA), nil } -// todo - move to CTF -func FundAddress(client blockchain.EVMClient, sendingKey string, fundingToSendEth *big.Float) error { - address := common.HexToAddress(sendingKey) - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ - To: &address, - }) - if err != nil { - return err - } - err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) - if err != nil { - return err - } - return nil -} - // todo - move to CTF func GetTxFromAddress(tx *types.Transaction) (string, error) { from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) return from.String(), err } -// todo - move to CTF -func GetTxByHash(ctx context.Context, client blockchain.EVMClient, hash common.Hash) (*types.Transaction, bool, error) { - return client.(*blockchain.EthereumMultinodeClient). - DefaultClient.(*blockchain.EthereumClient). - Client. - TransactionByHash(ctx, hash) -} - // todo - move to CTF func DecodeTxInputData(abiString string, data []byte) (map[string]interface{}, error) { jsonABI, err := abi.JSON(strings.NewReader(abiString)) @@ -523,42 +501,50 @@ func DecodeTxInputData(abiString string, data []byte) (map[string]interface{}, e return inputsMap, nil } -// todo - move to EVMClient +// todo - move to CTF func WaitForBlockNumberToBe( waitForBlockNumberToBe uint64, - client blockchain.EVMClient, + client *seth.Client, wg *sync.WaitGroup, timeout time.Duration, t testing.TB, + l zerolog.Logger, ) (uint64, error) { blockNumberChannel := make(chan uint64) errorChannel := make(chan error) testContext, testCancel := context.WithTimeout(context.Background(), timeout) defer testCancel() - - ticker := time.NewTicker(time.Second * 1) - var blockNumber uint64 + ticker := time.NewTicker(time.Second * 5) + var latestBlockNumber uint64 for { select { case <-testContext.Done(): ticker.Stop() wg.Done() - return blockNumber, + return latestBlockNumber, fmt.Errorf("timeout waiting for Block Number to be: %d. Last recorded block number was: %d", - waitForBlockNumberToBe, blockNumber) + waitForBlockNumberToBe, latestBlockNumber) case <-ticker.C: go func() { - currentBlockNumber, err := client.LatestBlockNumber(testcontext.Get(t)) + currentBlockNumber, err := client.Client.BlockNumber(testcontext.Get(t)) if err != nil { errorChannel <- err } + l.Info(). + Uint64("Latest Block Number", currentBlockNumber). + Uint64("Desired Block Number", waitForBlockNumberToBe). + Msg("Waiting for Block Number to be") blockNumberChannel <- currentBlockNumber }() - case blockNumber = <-blockNumberChannel: - if blockNumber == waitForBlockNumberToBe { + case latestBlockNumber = <-blockNumberChannel: + if latestBlockNumber >= waitForBlockNumberToBe { ticker.Stop() wg.Done() - return blockNumber, nil + l.Info(). + Uint64("Latest Block Number", latestBlockNumber). + Uint64("Desired Block Number", waitForBlockNumberToBe). + Msg("Desired Block Number reached!") + return latestBlockNumber, nil } case err := <-errorChannel: ticker.Stop() @@ -571,12 +557,12 @@ func WaitForBlockNumberToBe( // todo - move to EVMClient func RewindSimulatedChainToBlockNumber( ctx context.Context, - evmClient blockchain.EVMClient, + client *seth.Client, rpcURL string, rewindChainToBlockNumber uint64, l zerolog.Logger, ) (uint64, error) { - latestBlockNumberBeforeReorg, err := evmClient.LatestBlockNumber(ctx) + latestBlockNumberBeforeReorg, err := client.Client.BlockNumber(ctx) if err != nil { return 0, fmt.Errorf("error getting latest block number: %w", err) } @@ -593,12 +579,7 @@ func RewindSimulatedChainToBlockNumber( return 0, fmt.Errorf("error making reorg: %w", err) } - err = evmClient.WaitForEvents() - if err != nil { - return 0, fmt.Errorf("error waiting for events: %w", err) - } - - latestBlockNumberAfterReorg, err := evmClient.LatestBlockNumber(ctx) + latestBlockNumberAfterReorg, err := client.Client.BlockNumber(ctx) if err != nil { return 0, fmt.Errorf("error getting latest block number: %w", err) } diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index dd51e302744..61989def0c8 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -10,16 +10,18 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/seth" + ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - "github.com/smartcontractkit/chainlink/integration-tests/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/contracts" @@ -164,45 +166,32 @@ func SetAndGetOCR2VRFPluginConfig( return ocr2VRFPluginConfig } -func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV3, chainClient blockchain.EVMClient, subscriptionID, linkFundingAmount *big.Int) { +func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV3, subscriptionID, linkFundingAmount *big.Int) { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) require.NoError(t, err, "Error Abi encoding subscriptionID") _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) require.NoError(t, err, "Error sending Link token") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") } -func DeployOCR2VRFContracts(t *testing.T, contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) { - dkg, err := contractDeployer.DeployDKG() +func DeployOCR2VRFContracts(t *testing.T, chainClient *seth.Client, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) { + dkg, err := contracts.DeployDKG(chainClient) require.NoError(t, err, "Error deploying DKG Contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - - coordinator, err := contractDeployer.DeployOCR2VRFCoordinator(beaconPeriodBlocksCount, linkToken.Address()) + coordinator, err := contracts.DeployOCR2VRFCoordinator(chainClient, beaconPeriodBlocksCount, linkToken.Address()) require.NoError(t, err, "Error deploying OCR2VRFCoordinator Contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - - vrfBeacon, err := contractDeployer.DeployVRFBeacon(coordinator.Address(), linkToken.Address(), dkg.Address(), keyID) + vrfBeacon, err := contracts.DeployVRFBeacon(chainClient, coordinator.Address(), linkToken.Address(), dkg.Address(), keyID) require.NoError(t, err, "Error deploying VRFBeacon Contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - consumer, err := contractDeployer.DeployVRFBeaconConsumer(coordinator.Address(), beaconPeriodBlocksCount) + consumer, err := contracts.DeployVRFBeaconConsumer(chainClient, coordinator.Address(), beaconPeriodBlocksCount) require.NoError(t, err, "Error deploying VRFBeaconConsumer Contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") return dkg, coordinator, vrfBeacon, consumer } func RequestAndRedeemRandomness( t *testing.T, consumer contracts.VRFBeaconConsumer, - chainClient blockchain.EVMClient, vrfBeacon contracts.VRFBeacon, numberOfRandomWordsToRequest uint16, subscriptionID, @@ -218,9 +207,6 @@ func RequestAndRedeemRandomness( require.NoError(t, err, "Error requesting randomness from Consumer Contract") l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness requested from Consumer contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - requestID := getRequestId(t, consumer, receipt, confirmationDelay) newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout) @@ -229,8 +215,6 @@ func RequestAndRedeemRandomness( err = consumer.RedeemRandomness(subscriptionID, requestID) require.NoError(t, err, "Error redeeming randomness from Consumer Contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") return requestID } @@ -238,7 +222,6 @@ func RequestAndRedeemRandomness( func RequestRandomnessFulfillmentAndWaitForFulfilment( t *testing.T, consumer contracts.VRFBeaconConsumer, - chainClient blockchain.EVMClient, vrfBeacon contracts.VRFBeacon, numberOfRandomWordsToRequest uint16, subscriptionID *big.Int, @@ -257,18 +240,12 @@ func RequestRandomnessFulfillmentAndWaitForFulfilment( require.NoError(t, err, "Error requesting Randomness Fulfillment") l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness Fulfillment requested from Consumer contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - requestID := getRequestId(t, consumer, receipt, confirmationDelay) newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout) require.NoError(t, err, "Error waiting for NewTransmission event from VRF Beacon Contract") l.Info().Interface("NewTransmission event", newTransmissionEvent).Msg("Randomness Fulfillment transmitted by DON") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") - return requestID } @@ -290,12 +267,12 @@ func SetupOCR2VRFUniverse( t *testing.T, linkToken contracts.LinkToken, mockETHLinkFeed contracts.MockETHLINKFeed, - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, + chainClient *seth.Client, nodeAddresses []common.Address, chainlinkNodes []*client.ChainlinkK8sClient, testNetwork blockchain.EVMNetwork, ) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer, *big.Int) { + l := logging.GetTestLogger(t) // Deploy DKG contract // Deploy VRFCoordinator(beaconPeriodBlocks, linkAddress, linkEthfeedAddress) @@ -303,7 +280,6 @@ func SetupOCR2VRFUniverse( // Deploy Consumer Contract dkgContract, coordinatorContract, vrfBeaconContract, consumerContract := DeployOCR2VRFContracts( t, - contractDeployer, chainClient, linkToken, ocr2vrf_constants.BeaconPeriodBlocksCount, @@ -318,30 +294,23 @@ func SetupOCR2VRFUniverse( require.NoError(t, err, "Error setting Producer for VRFCoordinator contract") err = coordinatorContract.SetConfig(2.5e6, 160 /* 5 EVM words */) require.NoError(t, err, "Error setting config for VRFCoordinator contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") // Subscription: //1. Create Subscription err = coordinatorContract.CreateSubscription() require.NoError(t, err, "Error creating subscription in VRFCoordinator contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") subID, err := coordinatorContract.FindSubscriptionID() require.NoError(t, err) //2. Add Consumer to subscription err = coordinatorContract.AddConsumer(subID, consumerContract.Address()) require.NoError(t, err, "Error adding a consumer to a subscription in VRFCoordinator contract") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") //3. fund subscription with LINK token FundVRFCoordinatorV3Subscription( t, linkToken, coordinatorContract, - chainClient, subID, ocr2vrf_constants.LinkFundingAmount, ) @@ -352,10 +321,9 @@ func SetupOCR2VRFUniverse( require.NoError(t, err, "Error setting Payees in VRFBeacon Contract") // fund OCR Nodes (so that they can transmit) - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, ocr2vrf_constants.EthFundingAmount) + nodes := contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes) + err = actions_seth.FundChainlinkNodesFromRootAddress(l, chainClient, nodes, ocr2vrf_constants.EthFundingAmount) require.NoError(t, err, "Error funding Nodes") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for TXs to complete") bootstrapNode := chainlinkNodes[0] nonBootstrapNodes := chainlinkNodes[1:] diff --git a/integration-tests/actions/seth/actions.go b/integration-tests/actions/seth/actions.go index c43ae820f7e..91f03c36f1f 100644 --- a/integration-tests/actions/seth/actions.go +++ b/integration-tests/actions/seth/actions.go @@ -25,13 +25,13 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -293,7 +293,26 @@ func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPa Bool("Dynamic fees", client.Cfg.Network.EIP1559DynamicFees). Msg("Sent funds") - return client.WaitMined(ctx, logger, client.Client, signedTx) + receipt, receiptErr := client.WaitMined(ctx, logger, client.Client, signedTx) + if receiptErr != nil { + return nil, errors.Wrap(receiptErr, "failed to wait for transaction to be mined") + } + + if receipt.Status == 1 { + return receipt, nil + } + + tx, _, err := client.Client.TransactionByHash(ctx, signedTx.Hash()) + if err != nil { + return nil, errors.Wrap(err, "failed to get transaction by hash ") + } + + _, err = client.Decode(tx, receiptErr) + if err != nil { + return nil, err + } + + return receipt, nil } // DeployForwarderContracts first deploys Operator Factory and then uses it to deploy given number of diff --git a/integration-tests/actions/vrf/common/actions.go b/integration-tests/actions/vrf/common/actions.go index 4af9fd05572..fa7ba94ae70 100644 --- a/integration-tests/actions/vrf/common/actions.go +++ b/integration-tests/actions/vrf/common/actions.go @@ -11,9 +11,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -21,13 +22,14 @@ import ( ) func CreateFundAndGetSendingKeys( - client blockchain.EVMClient, + l zerolog.Logger, + client *seth.Client, node *VRFNode, chainlinkNodeFunding float64, numberOfTxKeysToCreate int, chainID *big.Int, ) ([]string, []common.Address, error) { - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(client, node, chainlinkNodeFunding, numberOfTxKeysToCreate, chainID) + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(l, client, node, chainlinkNodeFunding, numberOfTxKeysToCreate, chainID) if err != nil { return nil, nil, err } @@ -44,7 +46,8 @@ func CreateFundAndGetSendingKeys( } func CreateAndFundSendingKeys( - client blockchain.EVMClient, + l zerolog.Logger, + client *seth.Client, node *VRFNode, chainlinkNodeFunding float64, numberOfNativeTokenAddressesToCreate int, @@ -60,7 +63,11 @@ func CreateAndFundSendingKeys( return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) } newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.Attributes.Address) - err = actions.FundAddress(client, newTxKey.Data.Attributes.Address, big.NewFloat(chainlinkNodeFunding)) + _, err = actions_seth.SendFunds(l, client, actions_seth.FundsToSendPayload{ + ToAddress: common.HexToAddress(newTxKey.Data.Attributes.Address), + Amount: conversions.EtherToWei(big.NewFloat(chainlinkNodeFunding)), + PrivateKey: client.PrivateKeys[0], + }) if err != nil { return nil, err } @@ -79,13 +86,14 @@ func SetupBHSNode( l zerolog.Logger, bhsNode *VRFNode, ) error { - evmClient, err := env.GetEVMClient(chainID.Int64()) + sethClient, err := env.GetSethClient(chainID.Int64()) if err != nil { return err } bhsTXKeyAddressStrings, _, err := CreateFundAndGetSendingKeys( - evmClient, + l, + sethClient, bhsNode, txKeyFunding, numberOfTxKeysToCreate, @@ -158,12 +166,13 @@ func SetupBHFNode( l zerolog.Logger, bhfNode *VRFNode, ) error { - evmClient, err := env.GetEVMClient(chainID.Int64()) + sethClient, err := env.GetSethClient(chainID.Int64()) if err != nil { return err } bhfTXKeyAddressStrings, _, err := CreateFundAndGetSendingKeys( - evmClient, + l, + sethClient, bhfNode, txKeyFunding, numberOfTxKeysToCreate, @@ -306,26 +315,30 @@ func CreateVRFKeyOnVRFNode(vrfNode *VRFNode, l zerolog.Logger) (*client.VRFKey, return vrfKey, pubKeyCompressed, nil } -func FundNodesIfNeeded(ctx context.Context, existingEnvConfig *vrf_common_config.ExistingEnvConfig, client blockchain.EVMClient, l zerolog.Logger) error { +func FundNodesIfNeeded(ctx context.Context, existingEnvConfig *vrf_common_config.ExistingEnvConfig, client *seth.Client, l zerolog.Logger) error { if *existingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range existingEnvConfig.NodeSendingKeys { address := common.HexToAddress(sendingKey) - sendingKeyBalance, err := client.BalanceAt(ctx, address) + sendingKeyBalance, err := client.Client.BalanceAt(ctx, address, nil) if err != nil { return err } fundingAtLeast := conversions.EtherToWei(big.NewFloat(*existingEnvConfig.NodeSendingKeyFundingMin)) fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) - fundingToSendEth := conversions.WeiToEther(fundingToSendWei) log := l.Info(). Str("Sending Key", sendingKey). Str("Sending Key Current Balance", sendingKeyBalance.String()). Str("Should have at least", fundingAtLeast.String()) if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { log. - Str("Funding Amount in ETH", fundingToSendEth.String()). + Str("Funding Amount in wei", fundingToSendWei.String()). + Str("Funding Amount in ETH", conversions.WeiToEther(fundingToSendWei).String()). Msg("Funding Node's Sending Key") - err := actions.FundAddress(client, sendingKey, fundingToSendEth) + _, err := actions_seth.SendFunds(l, client, actions_seth.FundsToSendPayload{ + ToAddress: common.HexToAddress(sendingKey), + Amount: fundingToSendWei, + PrivateKey: client.PrivateKeys[0], + }) if err != nil { return err } diff --git a/integration-tests/actions/vrf/common/logging_helpers.go b/integration-tests/actions/vrf/common/logging_helpers.go index f9c8a031678..cf65798d54b 100644 --- a/integration-tests/actions/vrf/common/logging_helpers.go +++ b/integration-tests/actions/vrf/common/logging_helpers.go @@ -36,8 +36,10 @@ func LogRandomnessRequestedEvent( coordinator contracts.Coordinator, randomWordsRequestedEvent *contracts.CoordinatorRandomWordsRequested, isNativeBilling bool, + keyNum int, ) { l.Info(). + Int("KeyNum", keyNum). Str("Coordinator", coordinator.Address()). Bool("Native Billing", isNativeBilling). Str("Request ID", randomWordsRequestedEvent.RequestId.String()). @@ -58,8 +60,10 @@ func LogRandomWordsFulfilledEvent( coordinator contracts.Coordinator, randomWordsFulfilledEvent *contracts.CoordinatorRandomWordsFulfilled, isNativeBilling bool, + keyNum int, ) { l.Info(). + Int("KeyNum", keyNum). Bool("Native Billing", isNativeBilling). Str("Coordinator", coordinator.Address()). Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). diff --git a/integration-tests/actions/vrf/vrfv2/contract_steps.go b/integration-tests/actions/vrf/vrfv2/contract_steps.go index 495de0dd268..4f0ac9a5b6c 100644 --- a/integration-tests/actions/vrf/vrfv2/contract_steps.go +++ b/integration-tests/actions/vrf/vrfv2/contract_steps.go @@ -10,7 +10,8 @@ import ( "github.com/rs/zerolog" "github.com/shopspring/decimal" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" @@ -32,68 +33,46 @@ func DeployVRFV2Contracts( useVRFOwner bool, useTestCoordinator bool, ) (*vrfcommon.VRFContracts, error) { - bhs, err := env.ContractDeployer.DeployBlockhashStore() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) - } - - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, err } - err = evmClient.WaitForEvents() + bhs, err := contracts.DeployBlockhashStore(sethClient) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) } var coordinatorAddress string if useTestCoordinator { - testCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorTestV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + testCoordinator, err := contracts.DeployVRFCoordinatorTestV2(sethClient, linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinatorV2, err) } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } coordinatorAddress = testCoordinator.Address() } else { - coordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + coordinator, err := contracts.DeployVRFCoordinatorV2(sethClient, linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinatorV2, err) } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } coordinatorAddress = coordinator.Address() } - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(coordinatorAddress) + coordinator, err := contracts.LoadVRFCoordinatorV2(sethClient, coordinatorAddress) if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrLoadingCoordinator, err) } - batchCoordinator, err := env.ContractDeployer.DeployBatchVRFCoordinatorV2(coordinator.Address()) + batchCoordinator, err := contracts.DeployBatchVRFCoordinatorV2(sethClient, coordinator.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBatchCoordinatorV2, err) } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - if useVRFOwner { - vrfOwner, err := env.ContractDeployer.DeployVRFOwner(coordinatorAddress) + vrfOwner, err := contracts.DeployVRFOwner(sethClient, coordinatorAddress) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinatorV2, err) } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return &vrfcommon.VRFContracts{ CoordinatorV2: coordinator, BatchCoordinatorV2: batchCoordinator, @@ -115,10 +94,10 @@ func DeployVRFV2Contracts( }, nil } -func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinatorAddress string, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { +func DeployVRFV2Consumers(client *seth.Client, coordinatorAddress string, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { var consumers []contracts.VRFv2LoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinatorAddress) + loadTestConsumer, err := contracts.DeployVRFv2LoadTestConsumer(client, coordinatorAddress) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } @@ -127,10 +106,10 @@ func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinat return consumers, nil } -func DeployVRFV2WrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2Wrapper contracts.VRFV2Wrapper, consumerContractsAmount int) ([]contracts.VRFv2WrapperLoadTestConsumer, error) { +func DeployVRFV2WrapperConsumers(client *seth.Client, linkTokenAddress string, vrfV2Wrapper contracts.VRFV2Wrapper, consumerContractsAmount int) ([]contracts.VRFv2WrapperLoadTestConsumer, error) { var consumers []contracts.VRFv2WrapperLoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFV2WrapperLoadTestConsumer(linkTokenAddress, vrfV2Wrapper.Address()) + loadTestConsumer, err := contracts.DeployVRFV2WrapperLoadTestConsumer(client, linkTokenAddress, vrfV2Wrapper.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } @@ -140,30 +119,20 @@ func DeployVRFV2WrapperConsumers(contractDeployer contracts.ContractDeployer, li } func DeployVRFV2DirectFundingContracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, + client *seth.Client, linkTokenAddress string, linkEthFeedAddress string, coordinator contracts.VRFCoordinatorV2, consumerContractsAmount int, ) (*VRFV2WrapperContracts, error) { - vrfv2Wrapper, err := contractDeployer.DeployVRFV2Wrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) + vrfv2Wrapper, err := contracts.DeployVRFV2Wrapper(client, linkTokenAddress, linkEthFeedAddress, coordinator.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Wrapper, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - consumers, err := DeployVRFV2WrapperConsumers(contractDeployer, linkTokenAddress, vrfv2Wrapper, consumerContractsAmount) + consumers, err := DeployVRFV2WrapperConsumers(client, linkTokenAddress, vrfv2Wrapper, consumerContractsAmount) if err != nil { return nil, err } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return &VRFV2WrapperContracts{vrfv2Wrapper, consumers}, nil } @@ -232,20 +201,10 @@ func SetupVRFV2Contracts( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) } - - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return vrfContracts, nil } -func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, chainID int64, contracts *vrfcommon.VRFContracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { +func setupVRFOwnerContract(contracts *vrfcommon.VRFContracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { l.Info().Msg("Setting up VRFOwner contract") l.Info(). Str("Coordinator", contracts.CoordinatorV2.Address()). @@ -255,15 +214,6 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, chainID int64, contra if err != nil { return nil } - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil - } l.Info(). Str("VRFOwner", contracts.VRFOwner.Address()). Msg("Accepting VRF Ownership") @@ -271,10 +221,6 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, chainID int64, contra if err != nil { return nil } - err = evmClient.WaitForEvents() - if err != nil { - return nil - } l.Info(). Strs("Authorized Senders", allNativeTokenKeyAddressStrings). Str("VRFOwner", contracts.VRFOwner.Address()). @@ -283,23 +229,17 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, chainID int64, contra if err != nil { return nil } - err = evmClient.WaitForEvents() - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return err } func CreateFundSubsAndAddConsumers( - env *test_env.CLClusterTestEnv, - chainID int64, subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, consumers []contracts.VRFv2LoadTestConsumer, numberOfSubToCreate int, ) ([]uint64, error) { - subIDs, err := CreateSubsAndFund(env, chainID, subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) + subIDs, err := CreateSubsAndFund(subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) if err != nil { return nil, err } @@ -317,41 +257,20 @@ func CreateFundSubsAndAddConsumers( if err != nil { return nil, err } - - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return subIDs, nil } func CreateSubsAndFund( - env *test_env.CLClusterTestEnv, - chainID int64, subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subAmountToCreate int, ) ([]uint64, error) { - subs, err := CreateSubs(env, chainID, coordinator, subAmountToCreate) + subs, err := CreateSubs(coordinator, subAmountToCreate) if err != nil { return nil, err } - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - err = FundSubscriptions(env, chainID, subscriptionFundingAmountLink, linkToken, coordinator, subs) + err = FundSubscriptions(subscriptionFundingAmountLink, linkToken, coordinator, subs) if err != nil { return nil, err } @@ -359,15 +278,13 @@ func CreateSubsAndFund( } func CreateSubs( - env *test_env.CLClusterTestEnv, - chainID int64, coordinator contracts.VRFCoordinatorV2, subAmountToCreate int, ) ([]uint64, error) { var subIDArr []uint64 for i := 0; i < subAmountToCreate; i++ { - subID, err := CreateSubAndFindSubID(env, chainID, coordinator) + subID, err := CreateSubAndFindSubID(coordinator) if err != nil { return nil, err } @@ -391,26 +308,11 @@ func AddConsumersToSubs( return nil } -func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2) (uint64, error) { - tx, err := coordinator.CreateSubscription() +func CreateSubAndFindSubID(coordinator contracts.VRFCoordinatorV2) (uint64, error) { + receipt, err := coordinator.CreateSubscription() if err != nil { return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) } - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return 0, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - receipt, err := evmClient.GetTxReceipt(tx.Hash()) - if err != nil { - return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - //SubscriptionsCreated Log should be emitted with the subscription ID subID := receipt.Logs[0].Topics[1].Big().Uint64() @@ -418,37 +320,25 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordi } func FundSubscriptions( - env *test_env.CLClusterTestEnv, - chainID int64, subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subIDs []uint64, ) error { - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return err - } - for _, subID := range subIDs { //Link Billing amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) - err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, evmClient, subID, amountJuels) + err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, subID, amountJuels) if err != nil { return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) } } - err = evmClient.WaitForEvents() - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return nil } func FundVRFCoordinatorV2Subscription( linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, - chainClient blockchain.EVMClient, subscriptionID uint64, linkFundingAmountJuels *big.Int, ) error { @@ -460,7 +350,7 @@ func FundVRFCoordinatorV2Subscription( if err != nil { return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) } - return chainClient.WaitForEvents() + return nil } func DirectFundingRequestRandomnessAndWaitForFulfillment( @@ -487,6 +377,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfv2KeyData.KeyHash, + 0, ) randomWordsRequestedEvent, err := consumer.RequestRandomness( coordinator, @@ -519,6 +410,7 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, + keyNum int, ) (*contracts.CoordinatorRandomWordsRequested, *contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsRequestedEvent, err := RequestRandomness( l, @@ -531,6 +423,7 @@ func RequestRandomnessAndWaitForFulfillment( numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, + keyNum, ) if err != nil { return nil, nil, err @@ -558,6 +451,7 @@ func RequestRandomness( numberOfWords uint32, randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, + keyNum int, ) (*contracts.CoordinatorRandomWordsRequested, error) { logRandRequest( l, @@ -570,8 +464,9 @@ func RequestRandomness( randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfKeyData.KeyHash, + keyNum, ) - randomWordsRequestedEvent, err := consumer.RequestRandomness( + randomWordsRequestedEvent, err := consumer.RequestRandomnessFromKey( coordinator, vrfKeyData.KeyHash, subID, @@ -579,11 +474,12 @@ func RequestRandomness( callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, + keyNum, ) if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } - vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false, keyNum) return randomWordsRequestedEvent, err } @@ -603,7 +499,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( linkAddress common.Address, randomWordsFulfilledEventTimeout time.Duration, ) (*contracts.CoordinatorConfigSet, *contracts.CoordinatorRandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfv2KeyData.KeyHash) + logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfv2KeyData.KeyHash, 0) randomWordsRequestedEvent, err := consumer.RequestRandomWordsWithForceFulfill( coordinator, vrfv2KeyData.KeyHash, @@ -618,7 +514,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } - vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false, 0) errorChannel := make(chan error) configSetEventChannel := make(chan *contracts.CoordinatorConfigSet) @@ -673,7 +569,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( return nil, nil, nil, err case configSetEvent = <-configSetEventChannel: case randomWordsFulfilledEvent = <-randWordsFulfilledEventChannel: - vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false, 0) case randomWordsForcedEvent = <-randWordsForcedEventChannel: vrfcommon.LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) case <-time.After(randomWordsFulfilledEventTimeout): @@ -698,14 +594,14 @@ func WaitRandomWordsFulfilledEvent( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } - vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false, 0) return randomWordsFulfilledEvent, err } -func SetupVRFOwnerContractIfNeeded(useVRFOwner bool, env *test_env.CLClusterTestEnv, chainID int64, vrfContracts *vrfcommon.VRFContracts, vrfTXKeyAddressStrings []string, vrfTXKeyAddresses []common.Address, l zerolog.Logger) (*vrfcommon.VRFOwnerConfig, error) { +func SetupVRFOwnerContractIfNeeded(useVRFOwner bool, vrfContracts *vrfcommon.VRFContracts, vrfTXKeyAddressStrings []string, vrfTXKeyAddresses []common.Address, l zerolog.Logger) (*vrfcommon.VRFOwnerConfig, error) { var vrfOwnerConfig *vrfcommon.VRFOwnerConfig if useVRFOwner { - err := setupVRFOwnerContract(env, chainID, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) + err := setupVRFOwnerContract(vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) if err != nil { return nil, err } @@ -732,25 +628,19 @@ func SetupNewConsumersAndSubs( numberOfSubToCreate int, l zerolog.Logger, ) ([]contracts.VRFv2LoadTestConsumer, []uint64, error) { - consumers, err := DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), numberOfConsumerContractsToDeployAndAddToSub) - if err != nil { - return nil, nil, fmt.Errorf("err: %w", err) - } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { - return nil, []uint64{}, err + return nil, nil, err } - err = evmClient.WaitForEvents() + consumers, err := DeployVRFV2Consumers(sethClient, coordinator.Address(), numberOfConsumerContractsToDeployAndAddToSub) if err != nil { - return nil, nil, fmt.Errorf("%s, err: %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("err: %w", err) } l.Info(). Str("Coordinator", *testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress). Int("Number of Subs to create", numberOfSubToCreate). Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err := CreateFundSubsAndAddConsumers( - env, - chainID, big.NewFloat(*testConfig.VRFv2.General.SubscriptionFundingAmountLink), linkToken, coordinator, @@ -774,7 +664,7 @@ func CancelSubsAndReturnFunds(ctx context.Context, vrfContracts *vrfcommon.VRFCo l.Error().Err(err).Msg("Error checking if pending requests exist") } if !pendingRequestsExist { - _, err := vrfContracts.CoordinatorV2.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + _, _, err := vrfContracts.CoordinatorV2.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) if err != nil { l.Error().Err(err).Msg("Error canceling subscription") } diff --git a/integration-tests/actions/vrf/vrfv2/logging_helpers.go b/integration-tests/actions/vrf/vrfv2/logging_helpers.go index 248eebf45f1..ea6e15b2ff5 100644 --- a/integration-tests/actions/vrf/vrfv2/logging_helpers.go +++ b/integration-tests/actions/vrf/vrfv2/logging_helpers.go @@ -17,8 +17,10 @@ func logRandRequest( randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, keyhash [32]byte, + keyNum int, ) { l.Info(). + Int("KeyNum", keyNum). Str("Consumer", consumer). Str("Coordinator", coordinator). Uint64("SubID", subID). diff --git a/integration-tests/actions/vrf/vrfv2/setup_steps.go b/integration-tests/actions/vrf/vrfv2/setup_steps.go index c21ff0a11e6..2528d16dd77 100644 --- a/integration-tests/actions/vrf/vrfv2/setup_steps.go +++ b/integration-tests/actions/vrf/vrfv2/setup_steps.go @@ -13,9 +13,11 @@ import ( "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" @@ -121,13 +123,14 @@ func SetupVRFV2Environment( return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, nil, err } vrfTXKeyAddressStrings, vrfTXKeyAddresses, err := vrfcommon.CreateFundAndGetSendingKeys( - evmClient, + l, + sethClient, nodeTypeToNodeMap[vrfcommon.VRF], *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, numberOfTxKeysToCreate, @@ -136,14 +139,10 @@ func SetupVRFV2Environment( if err != nil { return nil, nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings - vrfOwnerConfig, err := SetupVRFOwnerContractIfNeeded(useVRFOwner, env, chainID, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) + vrfOwnerConfig, err := SetupVRFOwnerContractIfNeeded(useVRFOwner, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) if err != nil { return nil, nil, nil, err } @@ -248,15 +247,14 @@ func SetupVRFV2WrapperEnvironment( keyHash [32]byte, wrapperConsumerContractsAmount int, ) (*VRFV2WrapperContracts, *uint64, error) { - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, err } // Deploy VRF v2 direct funding contracts wrapperContracts, err := DeployVRFV2DirectFundingContracts( - env.ContractDeployer, - evmClient, + sethClient, linkToken.Address(), mockNativeLINKFeed.Address(), coordinator, @@ -265,10 +263,6 @@ func SetupVRFV2WrapperEnvironment( if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } vrfv2Config := vrfv2TestConfig.GetVRFv2Config() @@ -283,23 +277,15 @@ func SetupVRFV2WrapperEnvironment( if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } // Fetch wrapper subscription ID wrapperSubID, err := wrapperContracts.VRFV2Wrapper.GetSubID(ctx) if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } // Fund wrapper subscription - err = FundSubscriptions(env, chainID, big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) + err = FundSubscriptions(big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) if err != nil { return nil, nil, err } @@ -312,10 +298,6 @@ func SetupVRFV2WrapperEnvironment( if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } return wrapperContracts, &wrapperSubID, nil } @@ -338,7 +320,7 @@ func SetupVRFV2Universe( err error ) if *testConfig.VRFv2.General.UseExistingEnv { - vrfContracts, vrfKey, env, err = SetupVRFV2ForExistingEnv(ctx, t, testConfig, chainID, cleanupFn, l) + vrfContracts, vrfKey, env, err = SetupVRFV2ForExistingEnv(t, testConfig, chainID, cleanupFn, l) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 for Existing env", err) } @@ -374,27 +356,26 @@ func SetupVRFV2ForNewEnv( WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithChainlinkNodeLogScanner(chainlinkNodeLogScannerSettings). WithCustomCleanup(cleanupFn). + WithSeth(). Build() if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) } - env.ParallelTransactions(true) - - mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*testConfig.VRFv2.General.LinkNativeFeedResponse)) + sethClient, err := env.GetSethClientForSelectedNetwork() if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying mock ETH/LINK feed", err) + return nil, nil, nil, nil, err } - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + mockETHLinkFeed, err := contracts.DeployVRFMockETHLINKFeed(sethClient, big.NewInt(*testConfig.VRFv2.General.LinkNativeFeedResponse)) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying LINK contract", err) + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying mock ETH/LINK feed", err) } - evmClient, err := env.GetEVMClient(chainID) + linkToken, err := contracts.DeployLinkTokenContract(l, sethClient) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying LINK contract", err) } vrfContracts, vrfKey, nodeTypeToNode, err := SetupVRFV2Environment( @@ -408,7 +389,7 @@ func SetupVRFV2ForNewEnv( linkToken, mockETHLinkFeed, //register proving key against EOA address in order to return funds to this address - evmClient.GetDefaultWallet().Address(), + sethClient.MustGetRootKeyAddress().Hex(), newEnvConfig.NumberOfTxKeysToCreate, l, ) @@ -418,31 +399,37 @@ func SetupVRFV2ForNewEnv( return vrfContracts, vrfKey, env, nodeTypeToNode, nil } -func SetupVRFV2ForExistingEnv(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { +func SetupVRFV2ForExistingEnv(t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { commonExistingEnvConfig := testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&testConfig). WithCustomCleanup(cleanupFn). + WithSeth(). Build() if err != nil { return nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) } - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(*commonExistingEnvConfig.CoordinatorAddress) + client, err := env.GetSethClientForSelectedNetwork() + if err != nil { + return nil, nil, nil, err + } + coordinator, err := contracts.LoadVRFCoordinatorV2(client, *commonExistingEnvConfig.ConsumerAddress) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2", err) } - linkToken, err := env.ContractLoader.LoadLINKToken(*commonExistingEnvConfig.LinkAddress) + linkAddr := common.HexToAddress(*commonExistingEnvConfig.LinkAddress) + linkToken, err := contracts.LoadLinkTokenContract(l, client, linkAddr) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err) } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, nil, err } - err = vrfcommon.FundNodesIfNeeded(ctx, commonExistingEnvConfig, evmClient, l) + err = vrfcommon.FundNodesIfNeeded(testcontext.Get(t), commonExistingEnvConfig, sethClient, l) if err != nil { return nil, nil, nil, fmt.Errorf("err: %w", err) } @@ -492,7 +479,12 @@ func SetupSubsAndConsumersForExistingEnv( return nil, nil, fmt.Errorf("err: %w", err) } } else { - consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(*commonExistingEnvConfig.ConsumerAddress) + client, err := env.GetSethClient(chainID) + if err != nil { + return nil, nil, err + } + addr := common.HexToAddress(*commonExistingEnvConfig.ConsumerAddress) + consumer, err := contracts.LoadVRFv2LoadTestConsumer(client, addr) if err != nil { return nil, nil, fmt.Errorf("err: %w", err) } diff --git a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go index 7bd734b1026..6151931d566 100644 --- a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go @@ -10,7 +10,8 @@ import ( "github.com/rs/zerolog" "github.com/shopspring/decimal" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" @@ -23,37 +24,24 @@ import ( ) func DeployVRFV2_5Contracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, + chainClient *seth.Client, ) (*vrfcommon.VRFContracts, error) { - bhs, err := contractDeployer.DeployBlockhashStore() + bhs, err := contracts.DeployBlockhashStore(chainClient) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrDeployBlockHashStore, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - batchBHS, err := contractDeployer.DeployBatchBlockhashStore(bhs.Address()) + batchBHS, err := contracts.DeployBatchBlockhashStore(chainClient, bhs.Address()) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrDeployBatchBlockHashStore, err) } - coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) + coordinator, err := contracts.DeployVRFCoordinatorV2_5(chainClient, bhs.Address()) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployCoordinatorV2Plus, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - batchCoordinator, err := contractDeployer.DeployBatchVRFCoordinatorV2Plus(coordinator.Address()) + batchCoordinator, err := contracts.DeployBatchVRFCoordinatorV2Plus(chainClient, coordinator.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBatchCoordinatorV2Plus, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } return &vrfcommon.VRFContracts{ CoordinatorV2Plus: coordinator, BatchCoordinatorV2Plus: batchCoordinator, @@ -63,10 +51,10 @@ func DeployVRFV2_5Contracts( }, nil } -func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { +func DeployVRFV2PlusConsumers(client *seth.Client, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { var consumers []contracts.VRFv2PlusLoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFv2PlusLoadTestConsumer(coordinator.Address()) + loadTestConsumer, err := contracts.DeployVRFv2PlusLoadTestConsumer(client, coordinator.Address()) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAdvancedConsumer, err) } @@ -116,7 +104,6 @@ func VRFV2PlusUpgradedVersionRegisterProvingKey( func FundVRFCoordinatorV2_5Subscription( linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, - chainClient blockchain.EVMClient, subscriptionID *big.Int, linkFundingAmountJuels *big.Int, ) error { @@ -128,10 +115,11 @@ func FundVRFCoordinatorV2_5Subscription( if err != nil { return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrSendingLinkToken, err) } - return chainClient.WaitForEvents() + return nil } func CreateFundSubsAndAddConsumers( + ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, subscriptionFundingAmountNative *big.Float, @@ -142,6 +130,7 @@ func CreateFundSubsAndAddConsumers( numberOfSubToCreate int, ) ([]*big.Int, error) { subIDs, err := CreateSubsAndFund( + ctx, env, chainID, subscriptionFundingAmountNative, @@ -164,23 +153,12 @@ func CreateFundSubsAndAddConsumers( subToConsumersMap, coordinator, ) - if err != nil { - return nil, err - } - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - return subIDs, nil + return subIDs, err } func CreateSubsAndFund( + ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, subscriptionFundingAmountNative *big.Float, @@ -189,22 +167,11 @@ func CreateSubsAndFund( coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, ) ([]*big.Int, error) { - subs, err := CreateSubs(env, chainID, coordinator, subAmountToCreate) + subs, err := CreateSubs(ctx, env, chainID, coordinator, subAmountToCreate) if err != nil { return nil, err } - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } err = FundSubscriptions( - env, - chainID, subscriptionFundingAmountNative, subscriptionFundingAmountLink, linkToken, @@ -218,6 +185,7 @@ func CreateSubsAndFund( } func CreateSubs( + ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5, @@ -226,7 +194,7 @@ func CreateSubs( var subIDArr []*big.Int for i := 0; i < subAmountToCreate; i++ { - subID, err := CreateSubAndFindSubID(env, chainID, coordinator) + subID, err := CreateSubAndFindSubID(ctx, env, chainID, coordinator) if err != nil { return nil, err } @@ -250,21 +218,16 @@ func AddConsumersToSubs( return nil } -func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { +func CreateSubAndFindSubID(ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { tx, err := coordinator.CreateSubscription() if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrCreateVRFSubscription, err) } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - - receipt, err := evmClient.GetTxReceipt(tx.Hash()) + receipt, err := sethClient.Client.TransactionReceipt(ctx, tx.Hash()) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } @@ -276,19 +239,12 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordi } func FundSubscriptions( - env *test_env.CLClusterTestEnv, - chainID int64, subscriptionFundingAmountNative *big.Float, subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subIDs []*big.Int, ) error { - evmClient, err := env.GetEVMClient(chainID) - if err != nil { - return err - } - for _, subID := range subIDs { //Native Billing amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) @@ -301,15 +257,11 @@ func FundSubscriptions( } //Link Billing amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, evmClient, subID, amountJuels) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, subID, amountJuels) if err != nil { return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrFundSubWithLinkToken, err) } } - err = evmClient.WaitForEvents() - if err != nil { - return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } return nil } @@ -345,6 +297,7 @@ func RequestRandomness( isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger, + keyNum int, ) (*contracts.CoordinatorRandomWordsRequested, error) { LogRandRequest( l, @@ -354,8 +307,9 @@ func RequestRandomness( isNativeBilling, vrfKeyData.KeyHash, config, + keyNum, ) - randomWordsRequestedEvent, err := consumer.RequestRandomness( + randomWordsRequestedEvent, err := consumer.RequestRandomnessFromKey( coordinator, vrfKeyData.KeyHash, subID, @@ -364,11 +318,12 @@ func RequestRandomness( isNativeBilling, *config.NumberOfWords, *config.RandomnessRequestCountPerRequest, + keyNum, ) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRequestRandomness, err) } - vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling, keyNum) return randomWordsRequestedEvent, err } @@ -381,6 +336,7 @@ func RequestRandomnessAndWaitForFulfillment( isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger, + keyNum int, ) (*contracts.CoordinatorRandomWordsRequested, *contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsRequestedEvent, err := RequestRandomness( consumer, @@ -390,6 +346,7 @@ func RequestRandomnessAndWaitForFulfillment( isNativeBilling, config, l, + keyNum, ) if err != nil { return nil, nil, err @@ -402,6 +359,7 @@ func RequestRandomnessAndWaitForFulfillment( isNativeBilling, config.RandomWordsFulfilledEventTimeout.Duration, l, + keyNum, ) if err != nil { return nil, nil, err @@ -411,32 +369,21 @@ func RequestRandomnessAndWaitForFulfillment( } func DeployVRFV2PlusDirectFundingContracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, + sethClient *seth.Client, linkTokenAddress string, linkEthFeedAddress string, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int, wrapperSubId *big.Int, ) (*VRFV2PlusWrapperContracts, error) { - - vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address(), wrapperSubId) + vrfv2PlusWrapper, err := contracts.DeployVRFV2PlusWrapper(sethClient, linkTokenAddress, linkEthFeedAddress, coordinator.Address(), wrapperSubId) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployWrapper, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - - consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, vrfv2PlusWrapper, consumerContractsAmount) + consumers, err := DeployVRFV2PlusWrapperConsumers(sethClient, vrfv2PlusWrapper, consumerContractsAmount) if err != nil { return nil, err } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil } @@ -449,6 +396,7 @@ func WrapperRequestRandomness(consumer contracts.VRFv2PlusWrapperLoadTestConsume isNativeBilling, vrfKeyData.KeyHash, config, + 0, ) var randomWordsRequestedEvent *contracts.CoordinatorRandomWordsRequested var err error @@ -475,7 +423,7 @@ func WrapperRequestRandomness(consumer contracts.VRFv2PlusWrapperLoadTestConsume return nil, "", fmt.Errorf(vrfcommon.ErrGenericFormat, ErrRequestRandomnessDirectFundingLinkPayment, err) } } - vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling, 0) wrapperAddress, err := consumer.GetWrapper(context.Background()) if err != nil { return nil, "", fmt.Errorf("error getting wrapper address, err: %w", err) @@ -504,6 +452,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( isNativeBilling, config.RandomWordsFulfilledEventTimeout.Duration, l, + 0, ) } @@ -514,6 +463,7 @@ func WaitRandomWordsFulfilledEvent( isNativeBilling bool, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, + keyNum int, ) (*contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( contracts.RandomWordsFulfilledEventFilter{ @@ -526,14 +476,14 @@ func WaitRandomWordsFulfilledEvent( return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } - vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling, keyNum) return randomWordsFulfilledEvent, err } -func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { +func DeployVRFV2PlusWrapperConsumers(client *seth.Client, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapper.Address()) + loadTestConsumer, err := contracts.DeployVRFV2PlusWrapperLoadTestConsumer(client, vrfV2PlusWrapper.Address()) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAdvancedConsumer, err) } @@ -551,11 +501,11 @@ func SetupVRFV2PlusContracts( l zerolog.Logger, ) (*vrfcommon.VRFContracts, error) { l.Info().Msg("Deploying VRFV2 Plus contracts") - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, err } - vrfContracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, evmClient) + vrfContracts, err := DeployVRFV2_5Contracts(sethClient) if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployVRFV2_5Contracts, err) } @@ -583,15 +533,12 @@ func SetupVRFV2PlusContracts( if err != nil { return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrSetLinkNativeLinkFeed, err) } - err = evmClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } return vrfContracts, nil } func SetupNewConsumersAndSubs( + ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5, @@ -601,23 +548,20 @@ func SetupNewConsumersAndSubs( numberOfSubToCreate int, l zerolog.Logger, ) ([]contracts.VRFv2PlusLoadTestConsumer, []*big.Int, error) { - consumers, err := DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, consumerContractsAmount) - if err != nil { - return nil, nil, fmt.Errorf("err: %w", err) - } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() + consumers, err := DeployVRFV2PlusConsumers(sethClient, coordinator, consumerContractsAmount) if err != nil { - return nil, nil, fmt.Errorf("%s, err: %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf("err: %w", err) } l.Info(). Str("Coordinator", *testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress). Int("Number of Subs to create", numberOfSubToCreate). Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err := CreateFundSubsAndAddConsumers( + ctx, env, chainID, big.NewFloat(*testConfig.VRFv2Plus.General.SubscriptionFundingAmountNative), @@ -644,7 +588,7 @@ func CancelSubsAndReturnFunds(ctx context.Context, vrfContracts *vrfcommon.VRFCo l.Error().Err(err).Msg("Error checking if pending requests exist") } if !pendingRequestsExist { - _, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + _, _, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) if err != nil { l.Error().Err(err).Msg("Error canceling subscription") } diff --git a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go index b613298f1fd..1c6e2edaa0a 100644 --- a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go +++ b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go @@ -19,8 +19,11 @@ func LogRandRequest( subID *big.Int, isNativeBilling bool, keyHash [32]byte, - config *vrfv2plus_config.General) { + config *vrfv2plus_config.General, + keyNum int, +) { l.Info(). + Int("KeyNum", keyNum). Str("Consumer", consumer). Str("Coordinator", coordinator). Str("SubID", subID.String()). diff --git a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go index fdb5592767a..42f7a85d75e 100644 --- a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go @@ -14,6 +14,9 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" @@ -114,13 +117,14 @@ func SetupVRFV2_5Environment( return nil, nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrCreatingProvingKeyHash, err) } - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, nil, err } vrfTXKeyAddressStrings, _, err := vrfcommon.CreateFundAndGetSendingKeys( - evmClient, + l, + sethClient, nodeTypeToNodeMap[vrfcommon.VRF], *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, numberOfTxKeysToCreate, @@ -129,10 +133,6 @@ func SetupVRFV2_5Environment( if err != nil { return nil, nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings @@ -248,6 +248,7 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *v func SetupVRFV2PlusWrapperEnvironment( ctx context.Context, + l zerolog.Logger, env *test_env.CLClusterTestEnv, chainID int64, vrfv2PlusTestConfig types.VRFv2PlusTestConfig, @@ -258,33 +259,26 @@ func SetupVRFV2PlusWrapperEnvironment( wrapperConsumerContractsAmount int, ) (*VRFV2PlusWrapperContracts, *big.Int, error) { // external EOA has to create a subscription for the wrapper first - wrapperSubId, err := CreateSubAndFindSubID(env, chainID, coordinator) + wrapperSubId, err := CreateSubAndFindSubID(ctx, env, chainID, coordinator) if err != nil { return nil, nil, err } vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General - evmClient, err := env.GetEVMClient(chainID) + sethClient, err := env.GetSethClient(chainID) if err != nil { return nil, nil, err } wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( - env.ContractDeployer, - evmClient, + sethClient, linkToken.Address(), mockNativeLINKFeed.Address(), coordinator, wrapperConsumerContractsAmount, wrapperSubId, ) - if err != nil { - return nil, nil, err - } - - err = evmClient.WaitForEvents() - if err != nil { return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } @@ -295,10 +289,6 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } err = wrapperContracts.VRFV2PlusWrapper.SetConfig( *vrfv2PlusConfig.WrapperGasOverhead, *vrfv2PlusConfig.CoordinatorGasOverheadNative, @@ -317,25 +307,13 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - //fund sub wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(ctx) if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - err = FundSubscriptions( - env, - chainID, big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, @@ -354,20 +332,26 @@ func SetupVRFV2PlusWrapperEnvironment( if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) - } - //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) + //fund consumer with Eth (native token) + _, err = actions_seth.SendFunds(l, sethClient, actions_seth.FundsToSendPayload{ + ToAddress: common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), + Amount: conversions.EtherToWei(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)), + PrivateKey: sethClient.PrivateKeys[0], + }) if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() + + wrapperConsumerBalanceBeforeRequestWei, err := sethClient.Client.BalanceAt(ctx, common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil) if err != nil { - return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, err } + l.Info(). + Str("WrapperConsumerBalanceBeforeRequestWei", wrapperConsumerBalanceBeforeRequestWei.String()). + Str("WrapperConsumerAddress", wrapperContracts.LoadTestConsumers[0].Address()). + Msg("WrapperConsumerBalanceBeforeRequestWei") + return wrapperContracts, wrapperSubID, nil } @@ -389,7 +373,7 @@ func SetupVRFV2PlusUniverse( err error ) if *testConfig.VRFv2Plus.General.UseExistingEnv { - vrfContracts, vrfKey, env, err = SetupVRFV2PlusForExistingEnv(ctx, t, testConfig, chainID, cleanupFn, l) + vrfContracts, vrfKey, env, err = SetupVRFV2PlusForExistingEnv(t, testConfig, chainID, cleanupFn, l) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 Plus for Existing env", err) } @@ -424,19 +408,23 @@ func SetupVRFV2PlusForNewEnv( WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithChainlinkNodeLogScanner(chainlinkNodeLogScannerSettings). WithCustomCleanup(cleanupFn). + WithSeth(). Build() if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) } - env.ParallelTransactions(true) + sethClient, err := env.GetSethClient(chainID) + if err != nil { + return nil, nil, nil, nil, err + } - mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*testConfig.VRFv2Plus.General.LinkNativeFeedResponse)) + mockETHLinkFeed, err := contracts.DeployVRFMockETHLINKFeed(sethClient, big.NewInt(*testConfig.VRFv2Plus.General.LinkNativeFeedResponse)) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying mock ETH/LINK feed", err) } - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + linkToken, err := contracts.DeployLinkTokenContract(l, sethClient) if err != nil { return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying LINK contract", err) } @@ -458,31 +446,33 @@ func SetupVRFV2PlusForNewEnv( return vrfContracts, vrfKey, env, nodeTypeToNode, nil } -func SetupVRFV2PlusForExistingEnv(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { +func SetupVRFV2PlusForExistingEnv(t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { commonExistingEnvConfig := testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&testConfig). WithCustomCleanup(cleanupFn). + WithSeth(). Build() if err != nil { return nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) } - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(*commonExistingEnvConfig.CoordinatorAddress) + + sethClient, err := env.GetSethClient(chainID) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2_5", err) + return nil, nil, nil, err } - linkToken, err := env.ContractLoader.LoadLINKToken(*commonExistingEnvConfig.LinkAddress) + + coordinator, err := contracts.LoadVRFCoordinatorV2_5(sethClient, *commonExistingEnvConfig.CoordinatorAddress) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err) + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2_5", err) } - - evmClient, err := env.GetEVMClient(chainID) + linkToken, err := contracts.LoadLinkTokenContract(l, sethClient, common.HexToAddress(*commonExistingEnvConfig.LinkAddress)) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err) } - err = vrfcommon.FundNodesIfNeeded(ctx, commonExistingEnvConfig, evmClient, l) + err = vrfcommon.FundNodesIfNeeded(testcontext.Get(t), commonExistingEnvConfig, sethClient, l) if err != nil { return nil, nil, nil, fmt.Errorf("err: %w", err) } @@ -502,6 +492,7 @@ func SetupVRFV2PlusForExistingEnv(ctx context.Context, t *testing.T, testConfig } func SetupSubsAndConsumersForExistingEnv( + ctx context.Context, env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5, @@ -516,10 +507,15 @@ func SetupSubsAndConsumersForExistingEnv( consumers []contracts.VRFv2PlusLoadTestConsumer err error ) + sethClient, err := env.GetSethClient(chainID) + if err != nil { + return nil, nil, err + } if *testConfig.VRFv2Plus.General.UseExistingEnv { commonExistingEnvConfig := testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig if *commonExistingEnvConfig.CreateFundSubsAndAddConsumers { consumers, subIDs, err = SetupNewConsumersAndSubs( + ctx, env, chainID, coordinator, @@ -533,7 +529,7 @@ func SetupSubsAndConsumersForExistingEnv( return nil, nil, fmt.Errorf("err: %w", err) } } else { - consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(*commonExistingEnvConfig.ConsumerAddress) + consumer, err := contracts.LoadVRFv2PlusLoadTestConsumer(sethClient, *commonExistingEnvConfig.ConsumerAddress) if err != nil { return nil, nil, fmt.Errorf("err: %w", err) } @@ -547,6 +543,7 @@ func SetupSubsAndConsumersForExistingEnv( } } else { consumers, subIDs, err = SetupNewConsumersAndSubs( + ctx, env, chainID, coordinator, diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 4869dbcabd3..9ff697748dc 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" @@ -20,14 +19,16 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "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" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func TestOCR2VRFChaos(t *testing.T) { @@ -155,33 +156,30 @@ func TestOCR2VRFChaos(t *testing.T) { err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 3, 5, ChaosGroupMajority) require.NoError(t, err) - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") + testNetwork = utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) + chainClient, err := actions_seth.GetChainClientWithConfigFunction(testconfig, testNetwork, actions_seth.OneEphemeralKeysLiveTestnetCheckFn) + require.NoError(t, err, "Error creating seth client") + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &testconfig, chainClient) + err := actions_seth.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &testconfig) require.NoError(t, err, "Error tearing down environment") }) - chainClient.ParallelTransactions(true) - - linkToken, err := contractDeployer.DeployLinkTokenContract() + linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) require.NoError(t, err, "Error deploying LINK token") - mockETHLinkFeed, err := contractDeployer.DeployMockETHLINKFeed(ocr2vrf_constants.LinkEthFeedResponse) + mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( t, linkToken, mockETHLinkFeed, - contractDeployer, chainClient, nodeAddresses, chainlinkNodes, @@ -192,7 +190,6 @@ func TestOCR2VRFChaos(t *testing.T) { requestID := ocr2vrf_actions.RequestAndRedeemRandomness( t, consumerContract, - chainClient, vrfBeaconContract, ocr2vrf_constants.NumberOfRandomWordsToRequest, subID, @@ -219,7 +216,6 @@ func TestOCR2VRFChaos(t *testing.T) { requestID = ocr2vrf_actions.RequestAndRedeemRandomness( t, consumerContract, - chainClient, vrfBeaconContract, ocr2vrf_constants.NumberOfRandomWordsToRequest, subID, diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 5b40128d6aa..99198aa6352 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -78,7 +78,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" @@ -97,9 +96,7 @@ type ContractDeployer interface { LoadLinkToken(address common.Address) (LinkToken, error) DeployOffChainAggregator(linkAddr string, offchainOptions OffchainOptions) (OffchainAggregator, error) LoadOffChainAggregator(address *common.Address) (OffchainAggregator, error) - DeployVRFContract() (VRF, error) DeployMockETHLINKFeed(answer *big.Int) (MockETHLINKFeed, error) - DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) DeployMockGasFeed(answer *big.Int) (MockGasFeed, error) LoadGasFeed(address common.Address) (MockGasFeed, error) @@ -125,31 +122,8 @@ type ContractDeployer interface { DeployKeeperPerformDataChecker(expectedData []byte) (KeeperPerformDataChecker, error) DeployUpkeepCounter(testRange *big.Int, interval *big.Int) (UpkeepCounter, error) DeployUpkeepPerformCounterRestrictive(testRange *big.Int, averageEligibilityCadence *big.Int) (UpkeepPerformCounterRestrictive, error) - DeployVRFConsumer(linkAddr string, coordinatorAddr string) (VRFConsumer, error) - DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) - DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) - DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) - DeployVRFv2Consumer(coordinatorAddr string) (VRFv2Consumer, error) - DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) - DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) - DeployVRFv2PlusLoadTestConsumer(coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) - DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) - DeployVRFCoordinator(linkAddr string, bhsAddr string) (VRFCoordinator, error) - DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) - DeployBatchVRFCoordinatorV2(coordinatorAddress string) (BatchVRFCoordinatorV2, error) - DeployVRFCoordinatorV2_5(bhsAddr string) (VRFCoordinatorV2_5, error) - DeployBatchVRFCoordinatorV2Plus(coordinatorAddress string) (BatchVRFCoordinatorV2Plus, error) - DeployVRFCoordinatorV2PlusUpgradedVersion(bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) - DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) - DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string, subId *big.Int) (VRFV2PlusWrapper, error) - DeployDKG() (DKG, error) - DeployOCR2VRFCoordinator(beaconPeriodBlocksCount *big.Int, linkAddr string) (VRFCoordinatorV3, error) - DeployVRFBeacon(vrfCoordinatorAddress string, linkAddress string, dkgAddress string, keyId string) (VRFBeacon, error) - DeployVRFBeaconConsumer(vrfCoordinatorAddress string, beaconPeriodBlockCount *big.Int) (VRFBeaconConsumer, error) - DeployBlockhashStore() (BlockHashStore, error) DeployOperatorFactory(linkAddr string) (OperatorFactory, error) DeployStaking(params eth_contracts.StakingPoolConstructorParams) (Staking, error) - DeployBatchBlockhashStore(blockhashStoreAddr string) (BatchBlockhashStore, error) DeployFunctionsLoadTestClient(router string) (FunctionsLoadTestClient, error) DeployFunctionsOracleEventsMock() (FunctionsOracleEventsMock, error) DeployFunctionsBillingRegistryEventsMock() (FunctionsBillingRegistryEventsMock, error) @@ -533,7 +507,7 @@ func (e *EthereumContractDeployer) DeployOffchainAggregatorEventsMock() (Offchai func (e *EthereumContractDeployer) DeployLinkTokenContract() (LinkToken, error) { linkTokenAddress, _, instance, err := e.client.DeployContract("LINK Token", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return link_token_interface.DeployLinkToken(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) @@ -709,7 +683,7 @@ func (e *EthereumContractDeployer) DeployOracle(linkAddr string) (Oracle, error) func (e *EthereumContractDeployer) DeployMockETHLINKFeed(answer *big.Int) (MockETHLINKFeed, error) { address, _, instance, err := e.client.DeployContract("MockETHLINKAggregator", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return mock_ethlink_aggregator_wrapper.DeployMockETHLINKAggregator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), answer) }) @@ -723,23 +697,6 @@ func (e *EthereumContractDeployer) DeployMockETHLINKFeed(answer *big.Int) (MockE }, err } -func (e *EthereumContractDeployer) DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) { - address, _, instance, err := e.client.DeployContract("VRFMockETHLINKAggregator", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_mock_ethlink_aggregator.DeployVRFMockETHLINKAggregator(auth, backend, answer) - }) - if err != nil { - return nil, err - } - return &EthereumVRFMockETHLINKFeed{ - client: e.client, - feed: instance.(*vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator), - address: address, - }, err -} - // LoadETHLINKFeed returns deployed on given address EthereumMockETHLINKFeed func (e *EthereumContractDeployer) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) { instance, err := e.client.LoadContract("MockETHLINKFeed", address, func( @@ -761,7 +718,7 @@ func (e *EthereumContractDeployer) LoadETHLINKFeed(address common.Address) (Mock func (e *EthereumContractDeployer) DeployMockGasFeed(answer *big.Int) (MockGasFeed, error) { address, _, instance, err := e.client.DeployContract("MockGasFeed", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return mock_gas_aggregator_wrapper.DeployMockGASAggregator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), answer) }) @@ -796,7 +753,7 @@ func (e *EthereumContractDeployer) LoadGasFeed(address common.Address) (MockGasF func (e *EthereumContractDeployer) DeployUpkeepTranscoder() (UpkeepTranscoder, error) { address, _, instance, err := e.client.DeployContract("UpkeepTranscoder", func( opts *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return upkeep_transcoder.DeployUpkeepTranscoder(opts, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) @@ -838,7 +795,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_con // deploy registrar 2.0 address, _, instance, err := e.client.DeployContract("KeeperRegistrar", func( opts *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registrar_wrapper2_0.DeployKeeperRegistrar(opts, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), registrarSettings.AutoApproveConfigType, registrarSettings.AutoApproveMaxAllowed, common.HexToAddress(registrarSettings.RegistryAddr), registrarSettings.MinLinkJuels) @@ -857,7 +814,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_con // deploy registrar 2.1 address, _, instance, err := e.client.DeployContract("AutomationRegistrar", func( opts *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { // set default TriggerType to 0(conditional), AutoApproveConfigType to 2(auto approve enabled), AutoApproveMaxAllowed to 1000 triggerConfigs := []registrar21.AutomationRegistrar21InitialTriggerConfig{ @@ -978,7 +935,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( case eth_contracts.RegistryVersion_1_0, eth_contracts.RegistryVersion_1_1: address, _, instance, err := e.client.DeployContract("KeeperRegistry1_1", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_1.DeployKeeperRegistry( auth, @@ -1010,7 +967,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( case eth_contracts.RegistryVersion_1_2: address, _, instance, err := e.client.DeployContract("KeeperRegistry1_2", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_2.DeployKeeperRegistry( auth, @@ -1048,7 +1005,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( case eth_contracts.RegistryVersion_1_3: logicAddress, _, _, err := e.client.DeployContract("KeeperRegistryLogic1_3", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_logic1_3.DeployKeeperRegistryLogic( auth, @@ -1070,7 +1027,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( address, _, instance, err := e.client.DeployContract("KeeperRegistry1_3", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_3.DeployKeeperRegistry( auth, @@ -1106,7 +1063,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( case eth_contracts.RegistryVersion_2_0: logicAddress, _, _, err := e.client.DeployContract("KeeperRegistryLogic2_0", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_logic2_0.DeployKeeperRegistryLogic( auth, @@ -1127,7 +1084,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( address, _, instance, err := e.client.DeployContract("KeeperRegistry2_0", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper2_0.DeployKeeperRegistry( @@ -1154,7 +1111,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( registryLogicBAddr, _, _, err := e.client.DeployContract("KeeperRegistryLogicB2_1", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return registrylogicb21.DeployKeeperRegistryLogicB( @@ -1177,7 +1134,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( registryLogicAAddr, _, _, err := e.client.DeployContract("KeeperRegistryLogicA2_1", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return registrylogica21.DeployKeeperRegistryLogicA( @@ -1195,7 +1152,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( address, _, _, err := e.client.DeployContract("KeeperRegistry2_1", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return registry21.DeployKeeperRegistry( auth, @@ -1231,28 +1188,28 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( if chainId == networks.ScrollMainnet.ChainID || chainId == networks.ScrollSepolia.ChainID { chainModuleAddr, _, _, err = e.client.DeployContract("ScrollModule", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return scroll_module.DeployScrollModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else if chainId == networks.ArbitrumMainnet.ChainID || chainId == networks.ArbitrumSepolia.ChainID { chainModuleAddr, _, _, err = e.client.DeployContract("ArbitrumModule", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return arbitrum_module.DeployArbitrumModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else if chainId == networks.OptimismMainnet.ChainID || chainId == networks.OptimismSepolia.ChainID { chainModuleAddr, _, _, err = e.client.DeployContract("OptimismModule", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return optimism_module.DeployOptimismModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else { chainModuleAddr, _, _, err = e.client.DeployContract("ChainModuleBase", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return chain_module_base.DeployChainModuleBase(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) @@ -1277,7 +1234,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( } registryLogicBAddr, _, _, err := e.client.DeployContract("AutomationRegistryLogicB2_2", func( auth *bind.TransactOpts, - backend bind.ContractBackend, + _ bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return registrylogicb22.DeployAutomationRegistryLogicB( diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index f492adc3286..a81643b17c0 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,9 @@ package contracts import ( "errors" + "fmt" + + "github.com/smartcontractkit/seth" "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" @@ -18,8 +21,6 @@ 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/generated/vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" @@ -45,12 +46,6 @@ type ContractLoader interface { LoadMercuryRewardManager(addr common.Address) (MercuryRewardManager, error) LoadWERC20Mock(addr common.Address) (WERC20Mock, error) - - // VRF - LoadVRFCoordinatorV2(addr string) (VRFCoordinatorV2, error) - LoadVRFv2LoadTestConsumer(addr string) (VRFv2LoadTestConsumer, error) - LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) - LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) } // NewContractLoader returns an instance of a contract Loader based on the client type @@ -368,74 +363,44 @@ func (e *EthereumContractLoader) LoadWERC20Mock(addr common.Address) (WERC20Mock }, err } -func (e *EthereumContractLoader) LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) { +func LoadVRFCoordinatorV2_5(seth *seth.Client, addr string) (VRFCoordinatorV2_5, error) { address := common.HexToAddress(addr) - instance, err := e.client.LoadContract("VRFCoordinatorV2_5", address, func( - address common.Address, - backend bind.ContractBackend, - ) (interface{}, error) { - return vrf_coordinator_v2_5.NewVRFCoordinatorV25(address, backend) - }) + abi, err := vrf_coordinator_v2_5.VRFCoordinatorV25MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2_5{}, fmt.Errorf("failed to get VRFCoordinatorV2_5 ABI: %w", err) } - return &EthereumVRFCoordinatorV2_5{ - address: &address, - client: e.client, - coordinator: instance.(*vrf_coordinator_v2_5.VRFCoordinatorV25), - }, err -} + seth.ContractStore.AddABI("VRFCoordinatorV2_5", *abi) + seth.ContractStore.AddBIN("VRFCoordinatorV2_5", common.FromHex(vrf_coordinator_v2_5.VRFCoordinatorV25MetaData.Bin)) -func (e *EthereumContractLoader) LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) { - address := common.HexToAddress(addr) - instance, err := e.client.LoadContract("VRFV2PlusLoadTestWithMetrics", address, func( - address common.Address, - backend bind.ContractBackend, - ) (interface{}, error) { - return vrf_v2plus_load_test_with_metrics.NewVRFV2PlusLoadTestWithMetrics(address, backend) - }) + contract, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(address, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2_5{}, fmt.Errorf("failed to instantiate VRFCoordinatorV2_5 instance: %w", err) } - return &EthereumVRFv2PlusLoadTestConsumer{ - client: e.client, - consumer: instance.(*vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetrics), - address: &address, - }, err + + return &EthereumVRFCoordinatorV2_5{ + client: seth, + address: address, + coordinator: contract, + }, nil } -func (e *EthereumContractLoader) LoadVRFCoordinatorV2(addr string) (VRFCoordinatorV2, error) { +func LoadVRFv2PlusLoadTestConsumer(seth *seth.Client, addr string) (VRFv2PlusLoadTestConsumer, error) { address := common.HexToAddress(addr) - instance, err := e.client.LoadContract("VRFCoordinatorV2", address, func( - address common.Address, - backend bind.ContractBackend, - ) (interface{}, error) { - return vrf_coordinator_v2.NewVRFCoordinatorV2(address, wrappers.MustNewWrappedContractBackend(e.client, nil)) - }) + abi, err := vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetricsMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFv2PlusLoadTestConsumer{}, fmt.Errorf("failed to get VRFV2PlusLoadTestWithMetrics ABI: %w", err) } - return &EthereumVRFCoordinatorV2{ - address: &address, - client: e.client, - coordinator: instance.(*vrf_coordinator_v2.VRFCoordinatorV2), - }, err -} + seth.ContractStore.AddABI("VRFV2PlusLoadTestWithMetrics", *abi) + seth.ContractStore.AddBIN("VRFV2PlusLoadTestWithMetrics", common.FromHex(vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetricsMetaData.Bin)) -func (e *EthereumContractLoader) LoadVRFv2LoadTestConsumer(addr string) (VRFv2LoadTestConsumer, error) { - address := common.HexToAddress(addr) - instance, err := e.client.LoadContract("VRFV2LoadTestWithMetrics", address, func( - address common.Address, - backend bind.ContractBackend, - ) (interface{}, error) { - return vrf_load_test_with_metrics.NewVRFV2LoadTestWithMetrics(address, backend) - }) + contract, err := vrf_v2plus_load_test_with_metrics.NewVRFV2PlusLoadTestWithMetrics(address, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { - return nil, err + return &EthereumVRFv2PlusLoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2PlusLoadTestWithMetrics instance: %w", err) } - return &EthereumVRFv2LoadTestConsumer{ - client: e.client, - consumer: instance.(*vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics), - address: &address, - }, err + + return &EthereumVRFv2PlusLoadTestConsumer{ + client: seth, + address: address, + consumer: contract, + }, nil } diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 97551a1b9ee..7529696a77b 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" @@ -57,26 +59,20 @@ type VRFCoordinatorV2 interface { ) error TransferOwnership(to common.Address) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) - CreateSubscription() (*types.Transaction, error) + CreateSubscription() (*types.Receipt, error) AddConsumer(subId uint64, consumerAddress string) error Address() string GetSubscription(ctx context.Context, subID uint64) (Subscription, error) GetOwner(ctx context.Context) (common.Address, error) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) - OwnerCancelSubscription(subID uint64) (*types.Transaction, error) + OwnerCancelSubscription(subID uint64) (*seth.DecodedTransaction, *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) + CancelSubscription(subID uint64, to common.Address) (*seth.DecodedTransaction, *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) ParseRandomWordsFulfilled(log types.Log) (*CoordinatorRandomWordsFulfilled, error) ParseLog(log types.Log) (generated.AbigenLog, error) - CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) FindSubscriptionID(subID uint64) (uint64, error) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) - WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) - WaitForSubscriptionCanceledEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) - WaitForSubscriptionConsumerAdded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) - WaitForSubscriptionConsumerRemoved(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) - WaitForSubscriptionCreatedEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) - WaitForSubscriptionFunded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) OracleWithdraw(recipient common.Address, amount *big.Int) error } @@ -104,24 +100,21 @@ type VRFCoordinatorV2_5 interface { HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) CreateSubscription() (*types.Transaction, error) GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) - Migrate(subId *big.Int, coordinatorAddress string) error + Migrate(subId *big.Int, coordinatorAddress string) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) RegisterMigratableCoordinator(migratableCoordinatorAddress string) error AddConsumer(subId *big.Int, consumerAddress string) error FundSubscriptionWithNative(subId *big.Int, nativeTokenAmount *big.Int) error Address() string PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) GetSubscription(ctx context.Context, subID *big.Int) (Subscription, error) - OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) - CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) + OwnerCancelSubscription(subID *big.Int) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) + CancelSubscription(subID *big.Int, to common.Address) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) Withdraw(recipient common.Address) error WithdrawNative(recipient common.Address) error GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) FindSubscriptionID(subID *big.Int) (*big.Int, error) - WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) - WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) - WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) ParseRandomWordsFulfilled(log types.Log) (*CoordinatorRandomWordsFulfilled, error) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) @@ -160,7 +153,6 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) FindSubscriptionID() (*big.Int, error) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) - WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMigrationCompleted, error) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) ParseRandomWordsFulfilled(log types.Log) (*CoordinatorRandomWordsFulfilled, error) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) @@ -237,6 +229,16 @@ type VRFv2LoadTestConsumer interface { numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) + RequestRandomnessFromKey( + coordinator Coordinator, + keyHash [32]byte, + subID uint64, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + keyNum int, + ) (*CoordinatorRandomWordsRequested, error) RequestRandomWordsWithForceFulfill( coordinator Coordinator, keyHash [32]byte, @@ -274,6 +276,16 @@ type VRFv2PlusLoadTestConsumer interface { numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) + RequestRandomnessFromKey( + coordinator Coordinator, + keyHash [32]byte, subID *big.Int, + requestConfirmations uint16, + callbackGasLimit uint32, + nativePayment bool, + numWords uint32, + requestCount uint16, + keyNum int, + ) (*CoordinatorRandomWordsRequested, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2plus_load_test_with_metrics.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 4ee9f842873..ec61ad68183 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -1357,9 +1357,6 @@ func (o *LegacyEthereumOffchainAggregator) SetConfig( return fmt.Errorf("no OCR keys found for node %v", node) } primaryOCRKey := ocrKeys.Data[0] - if err != nil { - return err - } p2pKeys, err := node.MustReadP2PKeys() if err != nil { return err diff --git a/integration-tests/contracts/ethereum_contracts_seth.go b/integration-tests/contracts/ethereum_contracts_seth.go index d1e6a2c8a80..803a0a3bcec 100644 --- a/integration-tests/contracts/ethereum_contracts_seth.go +++ b/integration-tests/contracts/ethereum_contracts_seth.go @@ -52,7 +52,7 @@ func LoadOffchainAggregator(l zerolog.Logger, seth *seth.Client, contractAddress seth.ContractStore.AddABI("OffChainAggregator", *abi) seth.ContractStore.AddBIN("OffChainAggregator", common.FromHex(offchainaggregator.OffchainAggregatorMetaData.Bin)) - ocr, err := offchainaggregator.NewOffchainAggregator(contractAddress, seth.Client) + ocr, err := offchainaggregator.NewOffchainAggregator(contractAddress, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) } @@ -144,9 +144,6 @@ func (o *EthereumOffchainAggregator) SetConfig( return fmt.Errorf("no OCR keys found for node %v", node) } primaryOCRKey := ocrKeys.Data[0] - if err != nil { - return err - } p2pKeys, err := node.MustReadP2PKeys() if err != nil { return err diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index 18948ec38df..4ef0740fdbc 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -12,8 +12,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" + "github.com/smartcontractkit/seth" + + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" @@ -22,94 +24,146 @@ import ( // EthereumDKG represents DKG contract type EthereumDKG struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client dkg *dkg.DKG } // EthereumVRFCoordinatorV3 represents VRFCoordinatorV3 contract type EthereumVRFCoordinatorV3 struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client vrfCoordinatorV3 *vrf_coordinator.VRFCoordinator } // EthereumVRFBeacon represents VRFBeacon contract type EthereumVRFBeacon struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client vrfBeacon *vrf_beacon.VRFBeacon } // EthereumVRFBeaconConsumer represents VRFBeaconConsumer contract type EthereumVRFBeaconConsumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client vrfBeaconConsumer *vrf_beacon_consumer.BeaconVRFConsumer } -// LegacyEthereumVRFCoordinator represents VRF coordinator contract -type LegacyEthereumVRFCoordinator struct { - address *common.Address - client blockchain.EVMClient - coordinator *solidity_vrf_coordinator_interface.VRFCoordinator -} - // DeployDKG deploys DKG contract -func (e *EthereumContractDeployer) DeployDKG() (DKG, error) { - address, _, instance, err := e.client.DeployContract("DKG", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return dkg.DeployDKG(auth, backend) - }) +func DeployDKG(seth *seth.Client) (DKG, error) { + abi, err := dkg.DKGMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumDKG{}, fmt.Errorf("failed to get DKG ABI: %w", err) + } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "DKG", + *abi, + common.FromHex(dkg.DKGMetaData.Bin)) + if err != nil { + return &EthereumDKG{}, fmt.Errorf("DKG instance deployment have failed: %w", err) + } + + contract, err := dkg.NewDKG(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumDKG{}, fmt.Errorf("failed to instantiate DKG instance: %w", err) } + return &EthereumDKG{ - client: e.client, - dkg: instance.(*dkg.DKG), - address: address, + client: seth, + dkg: contract, + address: data.Address, }, err } // DeployOCR2VRFCoordinator deploys CR2VRFCoordinator contract -func (e *EthereumContractDeployer) DeployOCR2VRFCoordinator(beaconPeriodBlocksCount *big.Int, linkAddress string) (VRFCoordinatorV3, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinatorV3", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator.DeployVRFCoordinator(auth, backend, beaconPeriodBlocksCount, common.HexToAddress(linkAddress)) - }) +func DeployOCR2VRFCoordinator(seth *seth.Client, beaconPeriodBlocksCount *big.Int, linkAddress string) (VRFCoordinatorV3, error) { + abi, err := vrf_coordinator.VRFCoordinatorMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV3{}, fmt.Errorf("failed to get VRFCoordinatorV3 ABI: %w", err) + } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorV3", + *abi, + common.FromHex(vrf_coordinator.VRFCoordinatorMetaData.Bin), + beaconPeriodBlocksCount, common.HexToAddress(linkAddress)) + if err != nil { + return &EthereumVRFCoordinatorV3{}, fmt.Errorf("VRFCoordinatorV3 instance deployment have failed: %w", err) + } + + contract, err := vrf_coordinator.NewVRFCoordinator(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinatorV3{}, fmt.Errorf("failed to instantiate VRFCoordinatorV3 instance: %w", err) } + return &EthereumVRFCoordinatorV3{ - client: e.client, - vrfCoordinatorV3: instance.(*vrf_coordinator.VRFCoordinator), - address: address, + client: seth, + vrfCoordinatorV3: contract, + address: data.Address, }, err } // DeployVRFBeacon deploys DeployVRFBeacon contract -func (e *EthereumContractDeployer) DeployVRFBeacon(vrfCoordinatorAddress string, linkAddress string, dkgAddress string, keyId string) (VRFBeacon, error) { +func DeployVRFBeacon(seth *seth.Client, vrfCoordinatorAddress string, linkAddress string, dkgAddress string, keyId string) (VRFBeacon, error) { + abi, err := vrf_beacon.VRFBeaconMetaData.GetAbi() + if err != nil { + return &EthereumVRFBeacon{}, fmt.Errorf("failed to get VRFBeacon ABI: %w", err) + } keyIDBytes, err := DecodeHexTo32ByteArray(keyId) if err != nil { return nil, err } - address, _, instance, err := e.client.DeployContract("VRFBeacon", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_beacon.DeployVRFBeacon(auth, backend, common.HexToAddress(linkAddress), common.HexToAddress(vrfCoordinatorAddress), common.HexToAddress(dkgAddress), keyIDBytes) - }) + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFBeacon", + *abi, + common.FromHex(vrf_beacon.VRFBeaconMetaData.Bin), + common.HexToAddress(linkAddress), common.HexToAddress(vrfCoordinatorAddress), common.HexToAddress(dkgAddress), keyIDBytes) if err != nil { - return nil, err + return &EthereumVRFBeacon{}, fmt.Errorf("VRFBeacon instance deployment have failed: %w", err) } + + contract, err := vrf_beacon.NewVRFBeacon(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFBeacon{}, fmt.Errorf("failed to instantiate VRFBeacon instance: %w", err) + } + return &EthereumVRFBeacon{ - client: e.client, - vrfBeacon: instance.(*vrf_beacon.VRFBeacon), - address: address, + client: seth, + vrfBeacon: contract, + address: data.Address, + }, err +} + +// DeployBatchBlockhashStore deploys DeployBatchBlockhashStore contract +func DeployBatchBlockhashStore(seth *seth.Client, blockhashStoreAddr string) (BatchBlockhashStore, error) { + abi, err := batch_blockhash_store.BatchBlockhashStoreMetaData.GetAbi() + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to get BatchBlockhashStore ABI: %w", err) + } + data, err := seth.DeployContract( + seth.NewTXOpts(), + "BatchBlockhashStore", + *abi, + common.FromHex(batch_blockhash_store.BatchBlockhashStoreMetaData.Bin), + common.HexToAddress(blockhashStoreAddr)) + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("BatchBlockhashStore instance deployment have failed: %w", err) + } + + contract, err := batch_blockhash_store.NewBatchBlockhashStore(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to instantiate BatchBlockhashStore instance: %w", err) + } + + return &EthereumBatchBlockhashStore{ + client: seth, + batchBlockhashStore: contract, + address: data.Address, }, err } @@ -128,20 +182,30 @@ func DecodeHexTo32ByteArray(val string) ([32]byte, error) { } // DeployVRFBeaconConsumer deploys VRFv@ consumer contract -func (e *EthereumContractDeployer) DeployVRFBeaconConsumer(vrfCoordinatorAddress string, beaconPeriodBlockCount *big.Int) (VRFBeaconConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFBeaconConsumer", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_beacon_consumer.DeployBeaconVRFConsumer(auth, backend, common.HexToAddress(vrfCoordinatorAddress), false, beaconPeriodBlockCount) - }) +func DeployVRFBeaconConsumer(seth *seth.Client, vrfCoordinatorAddress string, beaconPeriodBlockCount *big.Int) (VRFBeaconConsumer, error) { + abi, err := vrf_beacon_consumer.BeaconVRFConsumerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFBeaconConsumer{}, fmt.Errorf("failed to get VRFBeaconConsumer ABI: %w", err) + } + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFBeaconConsumer", + *abi, + common.FromHex(vrf_beacon_consumer.BeaconVRFConsumerMetaData.Bin), + common.HexToAddress(vrfCoordinatorAddress), false, beaconPeriodBlockCount) + if err != nil { + return &EthereumVRFBeaconConsumer{}, fmt.Errorf("VRFBeaconConsumer instance deployment have failed: %w", err) } + + contract, err := vrf_beacon_consumer.NewBeaconVRFConsumer(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFBeaconConsumer{}, fmt.Errorf("failed to instantiate VRFBeaconConsumer instance: %w", err) + } + return &EthereumVRFBeaconConsumer{ - client: e.client, - vrfBeaconConsumer: instance.(*vrf_beacon_consumer.BeaconVRFConsumer), - address: address, + client: seth, + vrfBeaconConsumer: contract, + address: data.Address, }, err } @@ -154,20 +218,12 @@ func (dkgContract *EthereumDKG) AddClient(keyID string, clientAddress string) er if err != nil { return err } - opts, err := dkgContract.client.TransactionOpts(dkgContract.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := dkgContract.dkg.AddClient( - opts, + _, err = dkgContract.client.Decode(dkgContract.dkg.AddClient( + dkgContract.client.NewTXOpts(), keyIDBytes, common.HexToAddress(clientAddress), - ) - if err != nil { - return err - } - return dkgContract.client.ProcessTransaction(tx) - + )) + return err } func (dkgContract *EthereumDKG) SetConfig( @@ -178,23 +234,16 @@ func (dkgContract *EthereumDKG) SetConfig( offchainConfigVersion uint64, offchainConfig []byte, ) error { - opts, err := dkgContract.client.TransactionOpts(dkgContract.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := dkgContract.dkg.SetConfig( - opts, + _, err := dkgContract.client.Decode(dkgContract.dkg.SetConfig( + dkgContract.client.NewTXOpts(), signerAddresses, transmitterAddresses, f, onchainConfig, offchainConfigVersion, offchainConfig, - ) - if err != nil { - return err - } - return dkgContract.client.ProcessTransaction(tx) + )) + return err } func (dkgContract *EthereumDKG) WaitForTransmittedEvent(timeout time.Duration) (*dkg.DKGTransmitted, error) { @@ -242,42 +291,28 @@ func (coordinator *EthereumVRFCoordinatorV3) Address() string { } func (coordinator *EthereumVRFCoordinatorV3) SetProducer(producerAddress string) error { - opts, err := coordinator.client.TransactionOpts(coordinator.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := coordinator.vrfCoordinatorV3.SetProducer( - opts, + _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.SetProducer( + coordinator.client.NewTXOpts(), common.HexToAddress(producerAddress), - ) - if err != nil { - return err - } - return coordinator.client.ProcessTransaction(tx) + )) + return err } func (coordinator *EthereumVRFCoordinatorV3) CreateSubscription() error { - opts, err := coordinator.client.TransactionOpts(coordinator.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := coordinator.vrfCoordinatorV3.CreateSubscription( - opts, - ) - if err != nil { - return err - } - return coordinator.client.ProcessTransaction(tx) + _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.CreateSubscription( + coordinator.client.NewTXOpts(), + )) + return err } func (coordinator *EthereumVRFCoordinatorV3) FindSubscriptionID() (*big.Int, error) { fopts := &bind.FilterOpts{} - owner := coordinator.client.GetDefaultWallet().Address() + owner := coordinator.client.MustGetRootKeyAddress() subscriptionIterator, err := coordinator.vrfCoordinatorV3.FilterSubscriptionCreated( fopts, nil, - []common.Address{common.HexToAddress(owner)}, + []common.Address{owner}, ) if err != nil { return nil, err @@ -291,37 +326,23 @@ func (coordinator *EthereumVRFCoordinatorV3) FindSubscriptionID() (*big.Int, err } func (coordinator *EthereumVRFCoordinatorV3) AddConsumer(subId *big.Int, consumerAddress string) error { - opts, err := coordinator.client.TransactionOpts(coordinator.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := coordinator.vrfCoordinatorV3.AddConsumer( - opts, + _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.AddConsumer( + coordinator.client.NewTXOpts(), subId, common.HexToAddress(consumerAddress), - ) - if err != nil { - return err - } - return coordinator.client.ProcessTransaction(tx) + )) + return err } func (coordinator *EthereumVRFCoordinatorV3) SetConfig(maxCallbackGasLimit uint32, maxCallbackArgumentsLength uint32) error { - opts, err := coordinator.client.TransactionOpts(coordinator.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := coordinator.vrfCoordinatorV3.SetCallbackConfig( - opts, + _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.SetCallbackConfig( + coordinator.client.NewTXOpts(), vrf_coordinator.VRFCoordinatorCallbackConfig{ MaxCallbackGasLimit: maxCallbackGasLimit, MaxCallbackArgumentsLength: maxCallbackArgumentsLength, // 5 EVM words }, - ) - if err != nil { - return err - } - return coordinator.client.ProcessTransaction(tx) + )) + return err } func (beacon *EthereumVRFBeacon) Address() string { @@ -329,20 +350,12 @@ func (beacon *EthereumVRFBeacon) Address() string { } func (beacon *EthereumVRFBeacon) SetPayees(transmitterAddresses []common.Address, payeesAddresses []common.Address) error { - opts, err := beacon.client.TransactionOpts(beacon.client.GetDefaultWallet()) - if err != nil { - return err - } - - tx, err := beacon.vrfBeacon.SetPayees( - opts, + _, err := beacon.client.Decode(beacon.vrfBeacon.SetPayees( + beacon.client.NewTXOpts(), transmitterAddresses, payeesAddresses, - ) - if err != nil { - return err - } - return beacon.client.ProcessTransaction(tx) + )) + return err } func (beacon *EthereumVRFBeacon) SetConfig( @@ -353,23 +366,16 @@ func (beacon *EthereumVRFBeacon) SetConfig( offchainConfigVersion uint64, offchainConfig []byte, ) error { - opts, err := beacon.client.TransactionOpts(beacon.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := beacon.vrfBeacon.SetConfig( - opts, + _, err := beacon.client.Decode(beacon.vrfBeacon.SetConfig( + beacon.client.NewTXOpts(), signerAddresses, transmitterAddresses, f, onchainConfig, offchainConfigVersion, offchainConfig, - ) - if err != nil { - return err - } - return beacon.client.ProcessTransaction(tx) + )) + return err } func (beacon *EthereumVRFBeacon) WaitForConfigSetEvent(timeout time.Duration) (*vrf_beacon.VRFBeaconConfigSet, error) { @@ -415,7 +421,7 @@ func (beacon *EthereumVRFBeacon) WaitForNewTransmissionEvent(timeout time.Durati func (beacon *EthereumVRFBeacon) LatestConfigDigestAndEpoch(ctx context.Context) (vrf_beacon.LatestConfigDigestAndEpoch, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(beacon.client.GetDefaultWallet().Address()), + From: beacon.client.MustGetRootKeyAddress(), Context: ctx, } return beacon.vrfBeacon.LatestConfigDigestAndEpoch(opts) @@ -429,58 +435,37 @@ func (consumer *EthereumVRFBeaconConsumer) RequestRandomness( numWords uint16, subID, confirmationDelayArg *big.Int, ) (*types.Receipt, error) { - opts, err := consumer.client.TransactionOpts(consumer.client.GetDefaultWallet()) - if err != nil { - return nil, fmt.Errorf("TransactionOpts failed, err: %w", err) - } - tx, err := consumer.vrfBeaconConsumer.TestRequestRandomness( - opts, + tx, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRequestRandomness( + consumer.client.NewTXOpts(), numWords, subID, confirmationDelayArg, - ) + )) if err != nil { return nil, fmt.Errorf("TestRequestRandomness failed, err: %w", err) } - err = consumer.client.ProcessTransaction(tx) - if err != nil { - return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) - } - err = consumer.client.WaitForEvents() - - if err != nil { - return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) - } - receipt, err := consumer.client.GetTxReceipt(tx.Hash()) - if err != nil { - return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) - } log.Info().Interface("Sub ID", subID). Interface("Number of Words", numWords). Interface("Number of Confirmations", confirmationDelayArg). Msg("RequestRandomness called") - return receipt, nil + return tx.Receipt, nil } func (consumer *EthereumVRFBeaconConsumer) RedeemRandomness( subID, requestID *big.Int, ) error { - opts, err := consumer.client.TransactionOpts(consumer.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := consumer.vrfBeaconConsumer.TestRedeemRandomness( - opts, + _, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRedeemRandomness( + consumer.client.NewTXOpts(), subID, requestID, - ) + )) if err != nil { return err } log.Info().Interface("Sub ID", subID). Interface("Request ID", requestID). Msg("RedeemRandomness called") - return consumer.client.ProcessTransaction(tx) + return nil } func (consumer *EthereumVRFBeaconConsumer) RequestRandomnessFulfillment( @@ -490,48 +475,32 @@ func (consumer *EthereumVRFBeaconConsumer) RequestRandomnessFulfillment( callbackGasLimit uint32, arguments []byte, ) (*types.Receipt, error) { - opts, err := consumer.client.TransactionOpts(consumer.client.GetDefaultWallet()) - if err != nil { - return nil, err - } + opts := consumer.client.NewTXOpts() // overriding gas limit because gas estimated by TestRequestRandomnessFulfillment // is incorrect opts.GasLimit = uint64(requestGasLimit) - tx, err := consumer.vrfBeaconConsumer.TestRequestRandomnessFulfillment( + tx, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRequestRandomnessFulfillment( opts, subID, numWords, confirmationDelayArg, callbackGasLimit, arguments, - ) + )) if err != nil { return nil, fmt.Errorf("TestRequestRandomnessFulfillment failed, err: %w", err) } - err = consumer.client.ProcessTransaction(tx) - if err != nil { - return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) - } - err = consumer.client.WaitForEvents() - - if err != nil { - return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) - } - receipt, err := consumer.client.GetTxReceipt(tx.Hash()) - if err != nil { - return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) - } log.Info().Interface("Sub ID", subID). Interface("Number of Words", numWords). Interface("Number of Confirmations", confirmationDelayArg). Interface("Callback Gas Limit", callbackGasLimit). Msg("RequestRandomnessFulfillment called") - return receipt, nil + return tx.Receipt, nil } func (consumer *EthereumVRFBeaconConsumer) IBeaconPeriodBlocks(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(consumer.client.GetDefaultWallet().Address()), + From: consumer.client.MustGetRootKeyAddress(), Context: ctx, } return consumer.vrfBeaconConsumer.IBeaconPeriodBlocks(opts) @@ -539,7 +508,7 @@ func (consumer *EthereumVRFBeaconConsumer) IBeaconPeriodBlocks(ctx context.Conte func (consumer *EthereumVRFBeaconConsumer) GetRequestIdsBy(ctx context.Context, nextBeaconOutputHeight *big.Int, confDelay *big.Int) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(consumer.client.GetDefaultWallet().Address()), + From: consumer.client.MustGetRootKeyAddress(), Context: ctx, } return consumer.vrfBeaconConsumer.SRequestsIDs(opts, nextBeaconOutputHeight, confDelay) @@ -547,7 +516,7 @@ func (consumer *EthereumVRFBeaconConsumer) GetRequestIdsBy(ctx context.Context, func (consumer *EthereumVRFBeaconConsumer) GetRandomnessByRequestId(ctx context.Context, requestID *big.Int, numWordIndex *big.Int) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(consumer.client.GetDefaultWallet().Address()), + From: consumer.client.MustGetRootKeyAddress(), Context: ctx, } return consumer.vrfBeaconConsumer.SReceivedRandomnessByRequestID(opts, requestID, numWordIndex) diff --git a/integration-tests/contracts/ethereum_vrf_common.go b/integration-tests/contracts/ethereum_vrf_common.go index a57cfec8933..f0498b6efe6 100644 --- a/integration-tests/contracts/ethereum_vrf_common.go +++ b/integration-tests/contracts/ethereum_vrf_common.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" ) @@ -118,19 +117,3 @@ func ParseRandomWordsFulfilledLogs(coordinator Coordinator, logs []*types.Log) ( } return randomWordsFulfilledEventArr, nil } - -func RetrieveRequestRandomnessLogs(coordinator Coordinator, client blockchain.EVMClient, tx *types.Transaction) (*CoordinatorRandomWordsRequested, error) { - err := client.ProcessTransaction(tx) - if err != nil { - return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) - } - err = client.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) - } - receipt, err := client.GetTxReceipt(tx.Hash()) - if err != nil { - return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) - } - return parseRequestRandomnessLogs(coordinator, receipt.Logs) -} diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index 8484979164b..7b79ca01739 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -6,12 +6,12 @@ import ( "math/big" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" @@ -19,29 +19,61 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" ) -// LegacyEthereumBatchBlockhashStore represents BatchBlockhashStore contract -type LegacyEthereumBatchBlockhashStore struct { - address *common.Address - client blockchain.EVMClient - batchBlockhashStore *batch_blockhash_store.BatchBlockhashStore -} - -// LegacyEthereumBlockhashStore represents a blockhash store for VRF contract -type LegacyEthereumBlockhashStore struct { +// EthereumBlockhashStore represents a blockhash store for VRF contract +type EthereumBlockhashStore struct { address *common.Address - client blockchain.EVMClient + client *seth.Client blockHashStore *blockhash_store.BlockhashStore } -// LegacyEthereumVRFConsumer represents VRF consumer contract -type LegacyEthereumVRFConsumer struct { +// EthereumVRFCoordinator represents VRF coordinator contract +type EthereumVRFCoordinator struct { + address *common.Address + client *seth.Client + coordinator *solidity_vrf_coordinator_interface.VRFCoordinator +} + +type EthereumVRFCoordinatorTestV2 struct { + address *common.Address + client *seth.Client + coordinator *vrf_coordinator_test_v2.VRFCoordinatorTestV2 +} + +func (v *EthereumVRFCoordinatorTestV2) Address() string { + return v.address.Hex() +} + +// EthereumVRFConsumer represents VRF consumer contract +type EthereumVRFConsumer struct { address *common.Address - client blockchain.EVMClient + client *seth.Client consumer *solidity_vrf_consumer_interface.VRFConsumer } +// EthereumVRF represents a VRF contract +type EthereumVRF struct { + client *seth.Client + vrf *solidity_vrf_wrapper.VRF + address *common.Address +} + +type EthereumVRFMockETHLINKAggregator struct { + client *seth.Client + address *common.Address + contract *vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator +} + +// EthereumBatchBlockhashStore represents BatchBlockhashStore contract +type EthereumBatchBlockhashStore struct { + address common.Address + client *seth.Client + batchBlockhashStore *batch_blockhash_store.BatchBlockhashStore +} + // VRFConsumerRoundConfirmer is a header subscription that awaits for a certain VRF round to be completed type VRFConsumerRoundConfirmer struct { consumer VRFConsumer @@ -52,130 +84,294 @@ type VRFConsumerRoundConfirmer struct { done bool } -// LegacyEthereumVRF represents a VRF contract -type LegacyEthereumVRF struct { - client blockchain.EVMClient - vrf *solidity_vrf_wrapper.VRF - address *common.Address +// NewVRFConsumerRoundConfirmer provides a new instance of a NewVRFConsumerRoundConfirmer +func NewVRFConsumerRoundConfirmer( + contract VRFConsumer, + roundID *big.Int, + timeout time.Duration, +) *VRFConsumerRoundConfirmer { + ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) + return &VRFConsumerRoundConfirmer{ + consumer: contract, + roundID: roundID, + doneChan: make(chan struct{}), + context: ctx, + cancel: ctxCancel, + } } -// DeployVRFContract deploy VRF contract -func (e *EthereumContractDeployer) DeployVRFContract() (VRF, error) { - address, _, instance, err := e.client.DeployContract("VRF", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_wrapper.DeployVRF(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) - }) +// ReceiveHeader will query the latest VRFConsumer round and check to see whether the round has confirmed +func (f *VRFConsumerRoundConfirmer) ReceiveHeader(header blockchain.NodeHeader) error { + if f.done { + return nil + } + roundID, err := f.consumer.CurrentRoundID(context.Background()) + if err != nil { + return err + } + logFields := map[string]any{ + "Contract Address": f.consumer.Address(), + "Waiting for Round": f.roundID.Int64(), + "Current Round ID": roundID.Int64(), + "Header Number": header.Number.Uint64(), + } + if roundID.Int64() == f.roundID.Int64() { + randomness, err := f.consumer.RandomnessOutput(context.Background()) + if err != nil { + return err + } + log.Info().Fields(logFields).Uint64("Randomness", randomness.Uint64()).Msg("VRFConsumer round completed") + f.done = true + f.doneChan <- struct{}{} + } else { + log.Debug().Fields(logFields).Msg("Waiting for VRFConsumer round") + } + return nil +} + +// Wait is a blocking function that will wait until the round has confirmed, and timeout if the deadline has passed +func (f *VRFConsumerRoundConfirmer) Wait() error { + for { + select { + case <-f.doneChan: + f.cancel() + return nil + case <-f.context.Done(): + return fmt.Errorf("timeout waiting for VRFConsumer round to confirm: %d", f.roundID) + } + } +} + +func (v *EthereumBatchBlockhashStore) Address() string { + return v.address.Hex() +} + +func (a *EthereumVRFMockETHLINKAggregator) Address() string { + return a.address.Hex() +} + +func (a *EthereumVRFMockETHLINKAggregator) LatestRoundData() (*big.Int, error) { + data, err := a.contract.LatestRoundData(a.client.NewCallOpts()) if err != nil { return nil, err } - return &LegacyEthereumVRF{ - client: e.client, - vrf: instance.(*solidity_vrf_wrapper.VRF), - address: address, - }, err + return data.Ans, nil } -// DeployBlockhashStore deploys blockhash store used with VRF contract -func (e *EthereumContractDeployer) DeployBlockhashStore() (BlockHashStore, error) { - address, _, instance, err := e.client.DeployContract("BlockhashStore", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return blockhash_store.DeployBlockhashStore(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) - }) +func (a *EthereumVRFMockETHLINKAggregator) LatestRoundDataUpdatedAt() (*big.Int, error) { + data, err := a.contract.LatestRoundData(a.client.NewCallOpts()) if err != nil { return nil, err } - return &LegacyEthereumBlockhashStore{ - client: e.client, - blockHashStore: instance.(*blockhash_store.BlockhashStore), - address: address, + return data.UpdatedAt, nil +} + +func (a *EthereumVRFMockETHLINKAggregator) SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error { + _, err := a.client.Decode(a.contract.SetBlockTimestampDeduction(a.client.NewTXOpts(), blockTimestampDeduction)) + return err +} + +// DeployVRFContract deploy VRFv1 contract +func DeployVRFv1Contract(seth *seth.Client) (VRF, error) { + abi, err := solidity_vrf_wrapper.VRFMetaData.GetAbi() + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to get VRF ABI: %w", err) + } + + vrfDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRF", + *abi, + common.FromHex(solidity_vrf_wrapper.VRFMetaData.Bin)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("VRF instance deployment have failed: %w", err) + } + + vrf, err := solidity_vrf_wrapper.NewVRF(vrfDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to instantiate VRF instance: %w", err) + } + + return &EthereumVRF{ + client: seth, + vrf: vrf, + address: &vrfDeploymentData.Address, }, err } -// DeployBatchBlockhashStore deploys DeployBatchBlockhashStore contract -func (e *EthereumContractDeployer) DeployBatchBlockhashStore(blockhashStoreAddr string) (BatchBlockhashStore, error) { - address, _, instance, err := e.client.DeployContract("BatchBlockhashStore", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return batch_blockhash_store.DeployBatchBlockhashStore(auth, backend, common.HexToAddress(blockhashStoreAddr)) - }) +// DeployBlockhashStore deploys blockhash store used with VRF contract +func DeployBlockhashStore(seth *seth.Client) (BlockHashStore, error) { + abi, err := blockhash_store.BlockhashStoreMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumBlockhashStore{}, fmt.Errorf("failed to get BlockhashStore ABI: %w", err) + } + + storeDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "BlockhashStore", + *abi, + common.FromHex(blockhash_store.BlockhashStoreMetaData.Bin)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("BlockhashStore instance deployment have failed: %w", err) + } + + store, err := blockhash_store.NewBlockhashStore(storeDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("failed to instantiate BlockhashStore instance: %w", err) } - return &LegacyEthereumBatchBlockhashStore{ - client: e.client, - batchBlockhashStore: instance.(*batch_blockhash_store.BatchBlockhashStore), - address: address, + + return &EthereumBlockhashStore{ + client: seth, + blockHashStore: store, + address: &storeDeploymentData.Address, }, err } // DeployVRFCoordinator deploys VRF coordinator contract -func (e *EthereumContractDeployer) DeployVRFCoordinator(linkAddr string, bhsAddr string) (VRFCoordinator, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinator", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_coordinator_interface.DeployVRFCoordinator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr)) - }) +func DeployVRFCoordinator(seth *seth.Client, linkAddr, bhsAddr string) (VRFCoordinator, error) { + abi, err := solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to get VRFCoordinator ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinator", + *abi, + common.FromHex(solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(bhsAddr)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("VRFCoordinator instance deployment have failed: %w", err) + } + + coordinator, err := solidity_vrf_coordinator_interface.NewVRFCoordinator(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to instantiate VRFCoordinator instance: %w", err) + } + + return &EthereumVRFCoordinator{ + client: seth, + coordinator: coordinator, + address: &coordinatorDeploymentData.Address, + }, err +} + +func DeployVRFCoordinatorTestV2(seth *seth.Client, linkAddr, bhsAddr, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) { + abi, err := vrf_coordinator_test_v2.VRFCoordinatorTestV2MetaData.GetAbi() + if err != nil { + return &EthereumVRFCoordinatorTestV2{}, fmt.Errorf("failed to get VRFCoordinatorTestV2 ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorTestV2", + *abi, + common.FromHex(vrf_coordinator_test_v2.VRFCoordinatorTestV2MetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(bhsAddr), + common.HexToAddress(linkEthFeedAddr)) + if err != nil { + return &EthereumVRFCoordinatorTestV2{}, fmt.Errorf("VRFCoordinatorTestV2 instance deployment have failed: %w", err) + } + + coordinator, err := vrf_coordinator_test_v2.NewVRFCoordinatorTestV2(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinatorTestV2{}, fmt.Errorf("failed to instantiate VRFCoordinatorTestV2 instance: %w", err) } - return &LegacyEthereumVRFCoordinator{ - client: e.client, - coordinator: instance.(*solidity_vrf_coordinator_interface.VRFCoordinator), - address: address, + + return &EthereumVRFCoordinatorTestV2{ + client: seth, + coordinator: coordinator, + address: &coordinatorDeploymentData.Address, }, err } // DeployVRFConsumer deploys VRF consumer contract -func (e *EthereumContractDeployer) DeployVRFConsumer(linkAddr string, coordinatorAddr string) (VRFConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFConsumer", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_consumer_interface.DeployVRFConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr), common.HexToAddress(linkAddr)) - }) +func DeployVRFConsumer(seth *seth.Client, linkAddr, coordinatorAddr string) (VRFConsumer, error) { + abi, err := solidity_vrf_consumer_interface.VRFConsumerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFConsumer{}, fmt.Errorf("failed to get VRFConsumer ABI: %w", err) + } + + consumerDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFConsumer", + *abi, + common.FromHex(solidity_vrf_consumer_interface.VRFConsumerMetaData.Bin), + common.HexToAddress(coordinatorAddr), + common.HexToAddress(linkAddr), + ) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("VRFConsumer instance deployment have failed: %w", err) } - return &LegacyEthereumVRFConsumer{ - client: e.client, - consumer: instance.(*solidity_vrf_consumer_interface.VRFConsumer), - address: address, + + consumer, err := solidity_vrf_consumer_interface.NewVRFConsumer(consumerDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("failed to instantiate VRFConsumer instance: %w", err) + } + + return &EthereumVRFConsumer{ + client: seth, + consumer: consumer, + address: &consumerDeploymentData.Address, }, err } -func (v *LegacyEthereumBlockhashStore) Address() string { +func DeployVRFMockETHLINKFeed(seth *seth.Client, answer *big.Int) (VRFMockETHLINKFeed, error) { + abi, err := vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregatorMetaData.GetAbi() + if err != nil { + return &EthereumVRFMockETHLINKAggregator{}, fmt.Errorf("failed to get VRFMockETHLINKAggregator ABI: %w", err) + } + + deployment, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFMockETHLINKAggregator", + *abi, + common.FromHex(vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregatorMetaData.Bin), + answer, + ) + if err != nil { + return &EthereumVRFMockETHLINKAggregator{}, fmt.Errorf("VRFMockETHLINKAggregator deployment have failed: %w", err) + } + + contract, err := vrf_mock_ethlink_aggregator.NewVRFMockETHLINKAggregator(deployment.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFMockETHLINKAggregator{}, fmt.Errorf("failed to instantiate VRFMockETHLINKAggregator instance: %w", err) + } + + return &EthereumVRFMockETHLINKAggregator{ + client: seth, + contract: contract, + address: &deployment.Address, + }, err +} + +func (v *EthereumBlockhashStore) Address() string { return v.address.Hex() } -func (v *LegacyEthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { - opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), +func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { + blockHash, err := v.blockHashStore.GetBlockhash(&bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), Context: ctx, - } - blockHash, err := v.blockHashStore.GetBlockhash(opts, blockNumber) + }, blockNumber) if err != nil { return [32]byte{}, err } return blockHash, nil } -func (v *LegacyEthereumVRFCoordinator) Address() string { +func (v *EthereumVRFCoordinator) Address() string { return v.address.Hex() } // HashOfKey get a hash of proving key to use it as a request ID part for VRF -func (v *LegacyEthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { - opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), +func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { + hash, err := v.coordinator.HashOfKey(&bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), Context: ctx, - } - hash, err := v.coordinator.HashOfKey(opts, pubKey) + }, pubKey) if err != nil { return [32]byte{}, err } @@ -183,150 +379,55 @@ func (v *LegacyEthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2] } // RegisterProvingKey register VRF proving key -func (v *LegacyEthereumVRFCoordinator) RegisterProvingKey( +func (v *EthereumVRFCoordinator) RegisterProvingKey( fee *big.Int, oracleAddr string, publicProvingKey [2]*big.Int, jobID [32]byte, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterProvingKey(opts, fee, common.HexToAddress(oracleAddr), publicProvingKey, jobID) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), fee, common.HexToAddress(oracleAddr), publicProvingKey, jobID)) + return err } -func (v *LegacyEthereumVRFConsumer) Address() string { +func (v *EthereumVRFConsumer) Address() string { return v.address.Hex() } -func (v *LegacyEthereumVRFConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ - To: v.address, - }) - if err != nil { - return err - } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +func (v *EthereumVRFConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") } // RequestRandomness requests VRF randomness -func (v *LegacyEthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.TestRequestRandomness(opts, hash, fee) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) +func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { + _, err := v.client.Decode(v.consumer.TestRequestRandomness(v.client.NewTXOpts(), hash, fee)) + return err } // CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished -func (v *LegacyEthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { - opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), +func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { + return v.consumer.CurrentRoundID(&bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), Context: ctx, - } - return v.consumer.CurrentRoundID(opts) + }) } // RandomnessOutput get VRF randomness output -func (v *LegacyEthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { - opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), +func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { + return v.consumer.RandomnessOutput(&bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), Context: ctx, - } - out, err := v.consumer.RandomnessOutput(opts) - if err != nil { - return nil, err - } - return out, nil -} - -// NewVRFConsumerRoundConfirmer provides a new instance of a NewVRFConsumerRoundConfirmer -func NewVRFConsumerRoundConfirmer( - contract VRFConsumer, - roundID *big.Int, - timeout time.Duration, -) *VRFConsumerRoundConfirmer { - ctx, ctxCancel := context.WithTimeout(context.Background(), timeout) - return &VRFConsumerRoundConfirmer{ - consumer: contract, - roundID: roundID, - doneChan: make(chan struct{}), - context: ctx, - cancel: ctxCancel, - } -} - -// ReceiveHeader will query the latest VRFConsumer round and check to see whether the round has confirmed -func (f *VRFConsumerRoundConfirmer) ReceiveHeader(header blockchain.NodeHeader) error { - if f.done { - return nil - } - roundID, err := f.consumer.CurrentRoundID(context.Background()) - if err != nil { - return err - } - logFields := map[string]any{ - "Contract Address": f.consumer.Address(), - "Waiting for Round": f.roundID.Int64(), - "Current Round ID": roundID.Int64(), - "Header Number": header.Number.Uint64(), - } - if roundID.Int64() == f.roundID.Int64() { - randomness, err := f.consumer.RandomnessOutput(context.Background()) - if err != nil { - return err - } - log.Info().Fields(logFields).Uint64("Randomness", randomness.Uint64()).Msg("VRFConsumer round completed") - f.done = true - f.doneChan <- struct{}{} - } else { - log.Debug().Fields(logFields).Msg("Waiting for VRFConsumer round") - } - return nil -} - -// Wait is a blocking function that will wait until the round has confirmed, and timeout if the deadline has passed -func (f *VRFConsumerRoundConfirmer) Wait() error { - for { - select { - case <-f.doneChan: - f.cancel() - return nil - case <-f.context.Done(): - return fmt.Errorf("timeout waiting for VRFConsumer round to confirm: %d", f.roundID) - } - } + }) } // Fund sends specified currencies to the contract -func (v *LegacyEthereumVRF) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ - To: v.address, - }) - if err != nil { - return err - } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +func (v *EthereumVRF) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") } // ProofLength returns the PROOFLENGTH call from the VRF contract -func (v *LegacyEthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { - opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), - Context: ctxt, - } - return v.vrf.PROOFLENGTH(opts) -} - -func (v *LegacyEthereumBatchBlockhashStore) Address() string { - return v.address.Hex() +func (v *EthereumVRF) ProofLength(ctx context.Context) (*big.Int, error) { + return v.vrf.PROOFLENGTH(&bind.CallOpts{ + From: v.client.MustGetRootKeyAddress(), + Context: ctx, + }) } diff --git a/integration-tests/contracts/ethereum_vrf_contracts_seth.go b/integration-tests/contracts/ethereum_vrf_contracts_seth.go deleted file mode 100644 index f352e901a0c..00000000000 --- a/integration-tests/contracts/ethereum_vrf_contracts_seth.go +++ /dev/null @@ -1,247 +0,0 @@ -package contracts - -import ( - "context" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/seth" - - "github.com/smartcontractkit/chainlink/integration-tests/wrappers" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" -) - -// EthereumBlockhashStore represents a blockhash store for VRF contract -type EthereumBlockhashStore struct { - address *common.Address - client *seth.Client - blockHashStore *blockhash_store.BlockhashStore -} - -// EthereumVRFCoordinator represents VRF coordinator contract -type EthereumVRFCoordinator struct { - address *common.Address - client *seth.Client - coordinator *solidity_vrf_coordinator_interface.VRFCoordinator -} - -// EthereumVRFConsumer represents VRF consumer contract -type EthereumVRFConsumer struct { - address *common.Address - client *seth.Client - consumer *solidity_vrf_consumer_interface.VRFConsumer -} - -// EthereumVRF represents a VRF contract -type EthereumVRF struct { - client *seth.Client - vrf *solidity_vrf_wrapper.VRF - address *common.Address -} - -// DeployVRFContract deploy VRFv1 contract -func DeployVRFv1Contract(seth *seth.Client) (VRF, error) { - abi, err := solidity_vrf_wrapper.VRFMetaData.GetAbi() - if err != nil { - return &EthereumVRF{}, fmt.Errorf("failed to get VRF ABI: %w", err) - } - - vrfDeploymentData, err := seth.DeployContract( - seth.NewTXOpts(), - "VRF", - *abi, - common.FromHex(solidity_vrf_wrapper.VRFMetaData.Bin)) - if err != nil { - return &EthereumVRF{}, fmt.Errorf("VRF instance deployment have failed: %w", err) - } - - vrf, err := solidity_vrf_wrapper.NewVRF(vrfDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRF{}, fmt.Errorf("failed to instantiate VRF instance: %w", err) - } - - return &EthereumVRF{ - client: seth, - vrf: vrf, - address: &vrfDeploymentData.Address, - }, err -} - -// DeployBlockhashStore deploys blockhash store used with VRF contract -func DeployBlockhashStore(seth *seth.Client) (BlockHashStore, error) { - abi, err := blockhash_store.BlockhashStoreMetaData.GetAbi() - if err != nil { - return &EthereumBlockhashStore{}, fmt.Errorf("failed to get BlockhashStore ABI: %w", err) - } - - storeDeploymentData, err := seth.DeployContract( - seth.NewTXOpts(), - "BlockhashStore", - *abi, - common.FromHex(blockhash_store.BlockhashStoreMetaData.Bin)) - if err != nil { - return &EthereumBlockhashStore{}, fmt.Errorf("BlockhashStore instance deployment have failed: %w", err) - } - - store, err := blockhash_store.NewBlockhashStore(storeDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumBlockhashStore{}, fmt.Errorf("failed to instantiate BlockhashStore instance: %w", err) - } - - return &EthereumBlockhashStore{ - client: seth, - blockHashStore: store, - address: &storeDeploymentData.Address, - }, err -} - -// DeployVRFCoordinator deploys VRF coordinator contract -func DeployVRFCoordinator(seth *seth.Client, linkAddr, bhsAddr string) (VRFCoordinator, error) { - abi, err := solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.GetAbi() - if err != nil { - return &EthereumVRFCoordinator{}, fmt.Errorf("failed to get VRFCoordinator ABI: %w", err) - } - - coordinatorDeploymentData, err := seth.DeployContract( - seth.NewTXOpts(), - "VRFCoordinator", - *abi, - common.FromHex(solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.Bin), - common.HexToAddress(linkAddr), - common.HexToAddress(bhsAddr)) - if err != nil { - return &EthereumVRFCoordinator{}, fmt.Errorf("VRFCoordinator instance deployment have failed: %w", err) - } - - coordinator, err := solidity_vrf_coordinator_interface.NewVRFCoordinator(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRFCoordinator{}, fmt.Errorf("failed to instantiate VRFCoordinator instance: %w", err) - } - - return &EthereumVRFCoordinator{ - client: seth, - coordinator: coordinator, - address: &coordinatorDeploymentData.Address, - }, err -} - -// DeployVRFConsumer deploys VRF consumer contract -func DeployVRFConsumer(seth *seth.Client, linkAddr, coordinatorAddr string) (VRFConsumer, error) { - abi, err := solidity_vrf_consumer_interface.VRFConsumerMetaData.GetAbi() - if err != nil { - return &EthereumVRFConsumer{}, fmt.Errorf("failed to get VRFConsumer ABI: %w", err) - } - - consumerDeploymentData, err := seth.DeployContract( - seth.NewTXOpts(), - "VRFConsumer", - *abi, - common.FromHex(solidity_vrf_consumer_interface.VRFConsumerMetaData.Bin), - common.HexToAddress(coordinatorAddr), - common.HexToAddress(linkAddr), - ) - if err != nil { - return &EthereumVRFConsumer{}, fmt.Errorf("VRFConsumer instance deployment have failed: %w", err) - } - - consumer, err := solidity_vrf_consumer_interface.NewVRFConsumer(consumerDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRFConsumer{}, fmt.Errorf("failed to instantiate VRFConsumer instance: %w", err) - } - - return &EthereumVRFConsumer{ - client: seth, - consumer: consumer, - address: &consumerDeploymentData.Address, - }, err -} - -func (v *EthereumBlockhashStore) Address() string { - return v.address.Hex() -} - -func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { - blockHash, err := v.blockHashStore.GetBlockhash(&bind.CallOpts{ - From: v.client.Addresses[0], - Context: ctx, - }, blockNumber) - if err != nil { - return [32]byte{}, err - } - return blockHash, nil -} - -func (v *EthereumVRFCoordinator) Address() string { - return v.address.Hex() -} - -// HashOfKey get a hash of proving key to use it as a request ID part for VRF -func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { - hash, err := v.coordinator.HashOfKey(&bind.CallOpts{ - From: v.client.Addresses[0], - Context: ctx, - }, pubKey) - if err != nil { - return [32]byte{}, err - } - return hash, nil -} - -// RegisterProvingKey register VRF proving key -func (v *EthereumVRFCoordinator) RegisterProvingKey( - fee *big.Int, - oracleAddr string, - publicProvingKey [2]*big.Int, - jobID [32]byte, -) error { - _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), fee, common.HexToAddress(oracleAddr), publicProvingKey, jobID)) - return err -} - -func (v *EthereumVRFConsumer) Address() string { - return v.address.Hex() -} - -func (v *EthereumVRFConsumer) Fund(_ *big.Float) error { - panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") -} - -// RequestRandomness requests VRF randomness -func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { - _, err := v.client.Decode(v.consumer.TestRequestRandomness(v.client.NewTXOpts(), hash, fee)) - return err -} - -// CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished -func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { - return v.consumer.CurrentRoundID(&bind.CallOpts{ - From: v.client.Addresses[0], - Context: ctx, - }) -} - -// RandomnessOutput get VRF randomness output -func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { - return v.consumer.RandomnessOutput(&bind.CallOpts{ - From: v.client.Addresses[0], - Context: ctx, - }) -} - -// Fund sends specified currencies to the contract -func (v *EthereumVRF) Fund(_ *big.Float) error { - panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") -} - -// ProofLength returns the PROOFLENGTH call from the VRF contract -func (v *EthereumVRF) ProofLength(ctx context.Context) (*big.Int, error) { - return v.vrf.PROOFLENGTH(&bind.CallOpts{ - From: v.client.Addresses[0], - Context: ctx, - }) -} diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index e617d8a0c03..8786f201b29 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -8,20 +8,19 @@ import ( "strconv" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" @@ -31,61 +30,54 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" ) -// EthereumVRFCoordinatorV2 represents VRFV2 coordinator contract +type EthereumVRFOwner struct { + address common.Address + client *seth.Client + vrfOwner *vrf_owner.VRFOwner +} + type EthereumVRFCoordinatorV2 struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client coordinator *vrf_coordinator_v2.VRFCoordinatorV2 } type EthereumBatchVRFCoordinatorV2 struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client batchCoordinator *batch_vrf_coordinator_v2.BatchVRFCoordinatorV2 } -type EthereumVRFOwner struct { - address *common.Address - client blockchain.EVMClient - vrfOwner *vrf_owner.VRFOwner -} - -type EthereumVRFCoordinatorTestV2 struct { - address *common.Address - client blockchain.EVMClient - coordinator *vrf_coordinator_test_v2.VRFCoordinatorTestV2 -} - // EthereumVRFConsumerV2 represents VRFv2 consumer contract type EthereumVRFConsumerV2 struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrf_consumer_v2.VRFConsumerV2 } // EthereumVRFv2Consumer represents VRFv2 consumer contract type EthereumVRFv2Consumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrf_v2_consumer_wrapper.VRFv2Consumer } // EthereumVRFv2LoadTestConsumer represents VRFv2 consumer contract for performing Load Tests type EthereumVRFv2LoadTestConsumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics } type EthereumVRFV2Wrapper struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client wrapper *vrfv2_wrapper.VRFV2Wrapper } type EthereumVRFV2WrapperLoadTestConsumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer } @@ -96,164 +88,282 @@ type GetRequestConfig struct { } type EthereumVRFMockETHLINKFeed struct { - client blockchain.EVMClient + client *seth.Client feed *vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator - address *common.Address + address common.Address } -// DeployVRFCoordinatorV2 deploys VRFV2 coordinator contract -func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_v2.DeployVRFCoordinatorV2(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) - }) +func DeployVRFCoordinatorV2(seth *seth.Client, linkAddr, bhsAddr, linkEthFeedAddr string) (VRFCoordinatorV2, error) { + abi, err := vrf_coordinator_v2.VRFCoordinatorV2MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2{}, fmt.Errorf("failed to get VRFCoordinatorV2 ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorV2", + *abi, + common.FromHex(vrf_coordinator_v2.VRFCoordinatorV2MetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(bhsAddr), + common.HexToAddress(linkEthFeedAddr)) + if err != nil { + return &EthereumVRFCoordinatorV2{}, fmt.Errorf("VRFCoordinatorV2 instance deployment have failed: %w", err) } + + coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinatorV2{}, fmt.Errorf("failed to instantiate VRFCoordinatorV2 instance: %w", err) + } + return &EthereumVRFCoordinatorV2{ - client: e.client, - coordinator: instance.(*vrf_coordinator_v2.VRFCoordinatorV2), - address: address, + client: seth, + coordinator: coordinator, + address: coordinatorDeploymentData.Address, }, err } -func (e *EthereumContractDeployer) DeployBatchVRFCoordinatorV2(coordinatorAddress string) (BatchVRFCoordinatorV2, error) { - address, _, instance, err := e.client.DeployContract("BatchVRFCoordinatorV2", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return batch_vrf_coordinator_v2.DeployBatchVRFCoordinatorV2(auth, backend, common.HexToAddress(coordinatorAddress)) - }) +func LoadVRFCoordinatorV2(seth *seth.Client, address string) (*EthereumVRFCoordinatorV2, error) { + abi, err := vrf_coordinator_v2.VRFCoordinatorV2MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2{}, fmt.Errorf("failed to get VRFCoordinatorV2 ABI: %w", err) } - return &EthereumBatchVRFCoordinatorV2{ - client: e.client, - batchCoordinator: instance.(*batch_vrf_coordinator_v2.BatchVRFCoordinatorV2), - address: address, - }, err + seth.ContractStore.AddABI("VRFCoordinatorV2", *abi) + seth.ContractStore.AddBIN("VRFCoordinatorV2", common.FromHex(vrf_coordinator_v2.VRFCoordinatorV2MetaData.Bin)) + + contract, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(address), wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinatorV2{}, fmt.Errorf("failed to instantiate VRFCoordinatorV2 instance: %w", err) + } + + return &EthereumVRFCoordinatorV2{ + client: seth, + address: common.HexToAddress(address), + coordinator: contract, + }, nil } -func (e *EthereumContractDeployer) DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) { - address, _, instance, err := e.client.DeployContract("VRFOwner", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_owner.DeployVRFOwner(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) - }) +func DeployBatchVRFCoordinatorV2(seth *seth.Client, coordinatorAddress string) (BatchVRFCoordinatorV2, error) { + abi, err := batch_vrf_coordinator_v2.BatchVRFCoordinatorV2MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumBatchVRFCoordinatorV2{}, fmt.Errorf("failed to get BatchVRFCoordinatorV2 ABI: %w", err) } - return &EthereumVRFOwner{ - client: e.client, - vrfOwner: instance.(*vrf_owner.VRFOwner), - address: address, + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorV2Plus", + *abi, + common.FromHex(batch_vrf_coordinator_v2.BatchVRFCoordinatorV2MetaData.Bin), + common.HexToAddress(coordinatorAddress)) + if err != nil { + return &EthereumBatchVRFCoordinatorV2{}, fmt.Errorf("BatchVRFCoordinatorV2 instance deployment have failed: %w", err) + } + + contract, err := batch_vrf_coordinator_v2.NewBatchVRFCoordinatorV2(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBatchVRFCoordinatorV2{}, fmt.Errorf("failed to instantiate BatchVRFCoordinatorV2 instance: %w", err) + } + + return &EthereumBatchVRFCoordinatorV2{ + client: seth, + batchCoordinator: contract, + address: coordinatorDeploymentData.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinatorTestV2", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) - }) +func (v *EthereumBatchVRFCoordinatorV2) Address() string { + return v.address.Hex() +} + +func DeployVRFOwner(seth *seth.Client, coordinatorAddress string) (VRFOwner, error) { + abi, err := vrf_owner.VRFOwnerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFOwner{}, fmt.Errorf("failed to get VRFOwner ABI: %w", err) } - return &EthereumVRFCoordinatorTestV2{ - client: e.client, - coordinator: instance.(*vrf_coordinator_test_v2.VRFCoordinatorTestV2), - address: address, + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFOwner", + *abi, + common.FromHex(vrf_owner.VRFOwnerMetaData.Bin), + common.HexToAddress(coordinatorAddress)) + if err != nil { + return &EthereumVRFOwner{}, fmt.Errorf("VRFOwner instance deployment have failed: %w", err) + } + + contract, err := vrf_owner.NewVRFOwner(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFOwner{}, fmt.Errorf("failed to instantiate VRFOwner instance: %w", err) + } + + return &EthereumVRFOwner{ + client: seth, + vrfOwner: contract, + address: data.Address, }, err } // DeployVRFConsumerV2 deploys VRFv@ consumer contract -func (e *EthereumContractDeployer) DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) { - address, _, instance, err := e.client.DeployContract("VRFConsumerV2", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_consumer_v2.DeployVRFConsumerV2(auth, backend, common.HexToAddress(coordinatorAddr), common.HexToAddress(linkAddr)) - }) +func DeployVRFConsumerV2(seth *seth.Client, linkAddr, coordinatorAddr common.Address) (VRFConsumerV2, error) { + abi, err := vrf_consumer_v2.VRFConsumerV2MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFConsumerV2{}, fmt.Errorf("failed to get VRFConsumerV2 ABI: %w", err) + } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFConsumerV2", + *abi, + common.FromHex(vrf_consumer_v2.VRFConsumerV2MetaData.Bin), + coordinatorAddr, + linkAddr) + if err != nil { + return &EthereumVRFConsumerV2{}, fmt.Errorf("VRFConsumerV2 instance deployment have failed: %w", err) } + + contract, err := vrf_consumer_v2.NewVRFConsumerV2(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFConsumerV2{}, fmt.Errorf("failed to instantiate VRFConsumerV2 instance: %w", err) + } + return &EthereumVRFConsumerV2{ - client: e.client, - consumer: instance.(*vrf_consumer_v2.VRFConsumerV2), - address: address, + client: seth, + consumer: contract, + address: data.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFv2Consumer(coordinatorAddr string) (VRFv2Consumer, error) { - address, _, instance, err := e.client.DeployContract("VRFv2Consumer", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_v2_consumer_wrapper.DeployVRFv2Consumer(auth, backend, common.HexToAddress(coordinatorAddr)) - }) +func DeployVRFv2Consumer(seth *seth.Client, coordinatorAddr common.Address) (VRFv2Consumer, error) { + abi, err := vrf_v2_consumer_wrapper.VRFv2ConsumerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFv2Consumer{}, fmt.Errorf("failed to get VRFv2Consumer ABI: %w", err) + } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFv2Consumer", + *abi, + common.FromHex(vrf_v2_consumer_wrapper.VRFv2ConsumerMetaData.Bin), + coordinatorAddr) + if err != nil { + return &EthereumVRFv2Consumer{}, fmt.Errorf("VRFv2Consumer instance deployment have failed: %w", err) } + + contract, err := vrf_v2_consumer_wrapper.NewVRFv2Consumer(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFv2Consumer{}, fmt.Errorf("failed to instantiate VRFv2Consumer instance: %w", err) + } + return &EthereumVRFv2Consumer{ - client: e.client, - consumer: instance.(*vrf_v2_consumer_wrapper.VRFv2Consumer), - address: address, + client: seth, + consumer: contract, + address: data.Address, }, err } -// DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2Consumer, error) -func (e *EthereumContractDeployer) DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFV2LoadTestWithMetrics", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_load_test_with_metrics.DeployVRFV2LoadTestWithMetrics(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) - }) +func DeployVRFv2LoadTestConsumer(client *seth.Client, coordinatorAddr string) (VRFv2LoadTestConsumer, error) { + abi, err := vrf_load_test_with_metrics.VRFV2LoadTestWithMetricsMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFv2LoadTestConsumer{}, fmt.Errorf("failed to get VRFV2LoadTestWithMetrics ABI: %w", err) + } + + data, err := client.DeployContract( + client.NewTXOpts(), + "VRFV2LoadTestWithMetrics", + *abi, + common.FromHex(vrf_load_test_with_metrics.VRFV2LoadTestWithMetricsMetaData.Bin), + common.HexToAddress(coordinatorAddr)) + if err != nil { + return &EthereumVRFv2LoadTestConsumer{}, fmt.Errorf("VRFV2LoadTestWithMetrics instance deployment have failed: %w", err) + } + + contract, err := vrf_load_test_with_metrics.NewVRFV2LoadTestWithMetrics(data.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumVRFv2LoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2LoadTestWithMetrics instance: %w", err) } + return &EthereumVRFv2LoadTestConsumer{ - client: e.client, - consumer: instance.(*vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics), - address: address, + client: client, + consumer: contract, + address: data.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) { - address, _, instance, err := e.client.DeployContract("VRFV2Wrapper", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2_wrapper.DeployVRFV2Wrapper(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) - }) +func LoadVRFv2LoadTestConsumer(seth *seth.Client, addr common.Address) (VRFv2LoadTestConsumer, error) { + abi, err := vrf_load_test_with_metrics.VRFV2LoadTestWithMetricsMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFv2LoadTestConsumer{}, fmt.Errorf("failed to get VRFV2LoadTestWithMetrics ABI: %w", err) + } + seth.ContractStore.AddABI("VRFV2LoadTestWithMetrics", *abi) + seth.ContractStore.AddBIN("VRFV2LoadTestWithMetrics", common.FromHex(vrf_load_test_with_metrics.VRFV2LoadTestWithMetricsMetaData.Bin)) + + contract, err := vrf_load_test_with_metrics.NewVRFV2LoadTestWithMetrics(addr, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFv2LoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2LoadTestWithMetrics instance: %w", err) } + + return &EthereumVRFv2LoadTestConsumer{ + client: seth, + address: addr, + consumer: contract, + }, nil +} + +func DeployVRFV2Wrapper(client *seth.Client, linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) { + abi, err := vrfv2_wrapper.VRFV2WrapperMetaData.GetAbi() + if err != nil { + return &EthereumVRFV2Wrapper{}, fmt.Errorf("failed to get VRFV2Wrapper ABI: %w", err) + } + + data, err := client.DeployContract( + client.NewTXOpts(), + "VRFV2Wrapper", + *abi, + common.FromHex(vrfv2_wrapper.VRFV2WrapperMetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(linkEthFeedAddr), + common.HexToAddress(coordinatorAddr)) + if err != nil { + return &EthereumVRFV2Wrapper{}, fmt.Errorf("VRFV2Wrapper instance deployment have failed: %w", err) + } + + contract, err := vrfv2_wrapper.NewVRFV2Wrapper(data.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumVRFV2Wrapper{}, fmt.Errorf("failed to instantiate VRFV2Wrapper instance: %w", err) + } + return &EthereumVRFV2Wrapper{ - address: address, - client: e.client, - wrapper: instance.(*vrfv2_wrapper.VRFV2Wrapper), + client: client, + wrapper: contract, + address: data.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFV2WrapperLoadTestConsumer", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2_wrapper_load_test_consumer.DeployVRFV2WrapperLoadTestConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) - }) +func DeployVRFV2WrapperLoadTestConsumer(client *seth.Client, linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) { + abi, err := vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFV2WrapperLoadTestConsumer{}, fmt.Errorf("failed to get VRFV2WrapperLoadTestConsumer ABI: %w", err) } + + data, err := client.DeployContract( + client.NewTXOpts(), + "VRFV2WrapperLoadTestConsumer", + *abi, + common.FromHex(vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumerMetaData.Bin), + common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) + if err != nil { + return &EthereumVRFV2WrapperLoadTestConsumer{}, fmt.Errorf("VRFV2WrapperLoadTestConsumer instance deployment have failed: %w", err) + } + + contract, err := vrfv2_wrapper_load_test_consumer.NewVRFV2WrapperLoadTestConsumer(data.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumVRFV2WrapperLoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2WrapperLoadTestConsumer instance: %w", err) + } + return &EthereumVRFV2WrapperLoadTestConsumer{ - address: address, - client: e.client, - consumer: instance.(*vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer), + client: client, + consumer: contract, + address: data.Address, }, err } @@ -263,7 +373,7 @@ func (v *EthereumVRFCoordinatorV2) Address() string { func (v *EthereumVRFCoordinatorV2) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } hash, err := v.coordinator.HashOfKey(opts, pubKey) @@ -275,7 +385,7 @@ func (v *EthereumVRFCoordinatorV2) HashOfKey(ctx context.Context, pubKey [2]*big func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID uint64) (Subscription, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } subscription, err := v.coordinator.GetSubscription(opts, subID) @@ -293,7 +403,7 @@ func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID ui func (v *EthereumVRFCoordinatorV2) GetOwner(ctx context.Context) (common.Address, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } coordinatorOwnerAddress, err := v.coordinator.Owner(opts) @@ -305,7 +415,7 @@ func (v *EthereumVRFCoordinatorV2) GetOwner(ctx context.Context) (common.Address func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetRequestConfig, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } minConfirmations, maxGas, keyHashes, err := v.coordinator.GetRequestConfig(opts) @@ -323,7 +433,7 @@ func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetReq func (v *EthereumVRFCoordinatorV2) GetConfig(ctx context.Context) (vrf_coordinator_v2.GetConfig, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } config, err := v.coordinator.GetConfig(opts) @@ -335,7 +445,7 @@ func (v *EthereumVRFCoordinatorV2) GetConfig(ctx context.Context) (vrf_coordinat func (v *EthereumVRFCoordinatorV2) GetFallbackWeiPerUnitLink(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } fallbackWeiPerUnitLink, err := v.coordinator.GetFallbackWeiPerUnitLink(opts) @@ -347,7 +457,7 @@ func (v *EthereumVRFCoordinatorV2) GetFallbackWeiPerUnitLink(ctx context.Context func (v *EthereumVRFCoordinatorV2) GetFeeConfig(ctx context.Context) (vrf_coordinator_v2.GetFeeConfig, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } config, err := v.coordinator.GetFeeConfig(opts) @@ -358,83 +468,49 @@ func (v *EthereumVRFCoordinatorV2) GetFeeConfig(ctx context.Context) (vrf_coordi } func (v *EthereumVRFCoordinatorV2) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.SetConfig( - opts, + _, err := v.client.Decode(v.coordinator.SetConfig( + v.client.NewTXOpts(), minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2) RegisterProvingKey( oracleAddr string, publicProvingKey [2]*big.Int, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterProvingKey(opts, common.HexToAddress(oracleAddr), publicProvingKey) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), + common.HexToAddress(oracleAddr), publicProvingKey)) + return err } func (v *EthereumVRFCoordinatorV2) TransferOwnership(to common.Address) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.TransferOwnership(opts, to) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.TransferOwnership(v.client.NewTXOpts(), to)) + return err } -func (v *EthereumVRFCoordinatorV2) CreateSubscription() (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.coordinator.CreateSubscription(opts) - if err != nil { - return nil, err - } - return tx, v.client.ProcessTransaction(tx) +func (v *EthereumVRFCoordinatorV2) CreateSubscription() (*types.Receipt, error) { + tx, err := v.client.Decode(v.coordinator.CreateSubscription(v.client.NewTXOpts())) + return tx.Receipt, err } func (v *EthereumVRFCoordinatorV2) AddConsumer(subId uint64, consumerAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.AddConsumer( - opts, + _, err := v.client.Decode(v.coordinator.AddConsumer( + v.client.NewTXOpts(), subId, common.HexToAddress(consumerAddress), - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } pendingRequestExists, err := v.coordinator.PendingRequestExists(opts, subID) @@ -445,34 +521,34 @@ func (v *EthereumVRFCoordinatorV2) PendingRequestsExist(ctx context.Context, sub } func (v *EthereumVRFCoordinatorV2) OracleWithdraw(recipient common.Address, amount *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.OracleWithdraw(opts, recipient, amount) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.OracleWithdraw(v.client.NewTXOpts(), recipient, amount)) + return err } // OwnerCancelSubscription cancels subscription, // return funds to the subscription owner, // down not check if pending requests for a sub exist, // outstanding requests may fail onchain -func (v *EthereumVRFCoordinatorV2) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.coordinator.OwnerCancelSubscription( - opts, +func (v *EthereumVRFCoordinatorV2) OwnerCancelSubscription(subID uint64) (*seth.DecodedTransaction, *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { + tx, err := v.client.Decode(v.coordinator.OwnerCancelSubscription( + v.client.NewTXOpts(), subID, - ) - if err != nil { - return nil, err + )) + if err != nil { + return nil, nil, err + } + var subCanceledEvent *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled + for _, log := range tx.Receipt.Logs { + for _, topic := range log.Topics { + if topic.Cmp(vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled{}.Topic()) == 0 { + subCanceledEvent, err = v.coordinator.ParseSubscriptionCanceled(*log) + if err != nil { + return nil, nil, fmt.Errorf("parsing SubscriptionCanceled log failed, err: %w", err) + } + } + } } - return tx, v.client.ProcessTransaction(tx) + return tx, subCanceledEvent, err } func (v *EthereumVRFCoordinatorV2) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { @@ -521,24 +597,31 @@ func (v *EthereumVRFCoordinatorV2) ParseLog(log types.Log) (generated.AbigenLog, // CancelSubscription cancels subscription by Sub owner, // return funds to specified address, // checks if pending requests for a sub exist -func (v *EthereumVRFCoordinatorV2) CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.coordinator.CancelSubscription( - opts, +func (v *EthereumVRFCoordinatorV2) CancelSubscription(subID uint64, to common.Address) (*seth.DecodedTransaction, *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { + tx, err := v.client.Decode(v.coordinator.CancelSubscription( + v.client.NewTXOpts(), subID, to, - ) - if err != nil { - return nil, err + )) + if err != nil { + return nil, nil, err + } + var subCanceledEvent *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled + for _, log := range tx.Receipt.Logs { + for _, topic := range log.Topics { + if topic.Cmp(vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled{}.Topic()) == 0 { + subCanceledEvent, err = v.coordinator.ParseSubscriptionCanceled(*log) + if err != nil { + return nil, nil, fmt.Errorf("parsing SubscriptionCanceled log failed, err: %w", err) + } + } + } } - return tx, v.client.ProcessTransaction(tx) + return tx, subCanceledEvent, err } func (v *EthereumVRFCoordinatorV2) FindSubscriptionID(subID uint64) (uint64, error) { - owner := v.client.GetDefaultWallet().Address() + owner := v.client.MustGetRootKeyAddress() subscriptionIterator, err := v.coordinator.FilterSubscriptionCreated( nil, []uint64{subID}, @@ -580,126 +663,6 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(filter Rando } } -func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested) - subscription, err := v.coordinator.WatchRandomWordsRequested(nil, eventsChannel, keyHash, subID, sender) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for RandomWordsRequested event") - case event := <-eventsChannel: - return event, nil - } - } -} - -func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionFunded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded) - subscription, err := v.coordinator.WatchSubscriptionFunded(nil, eventsChannel, subID) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionFunded event") - case event := <-eventsChannel: - return event, nil - } - } -} - -func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCanceledEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled) - subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, subID) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionCanceled event") - case sub := <-eventsChannel: - return sub, nil - } - } -} - -func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCreatedEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated) - subscription, err := v.coordinator.WatchSubscriptionCreated(nil, eventsChannel, subID) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionCreated event") - case event := <-eventsChannel: - return event, nil - } - } -} - -func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerAdded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded) - subscription, err := v.coordinator.WatchSubscriptionConsumerAdded(nil, eventsChannel, subID) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionConsumerAdded event") - case event := <-eventsChannel: - return event, nil - } - } -} - -func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerRemoved(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) { - eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved) - subscription, err := v.coordinator.WatchSubscriptionConsumerRemoved(nil, eventsChannel, subID) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionConsumerRemoved event") - case event := <-eventsChannel: - return event, nil - } - } -} - func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) { eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) subscription, err := v.coordinator.WatchConfigSet(nil, eventsChannel) @@ -742,7 +705,7 @@ func (v *EthereumVRFConsumerV2) GetAllRandomWords(ctx context.Context, num int) words := make([]*big.Int, 0) for i := 0; i < num; i++ { word, err := v.consumer.SRandomWords(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, big.NewInt(int64(i))) if err != nil { @@ -754,42 +717,36 @@ func (v *EthereumVRFConsumerV2) GetAllRandomWords(ctx context.Context, num int) } // LoadExistingConsumer loads an EthereumVRFConsumerV2 with a specified address -func (v *EthereumVRFConsumerV2) LoadExistingConsumer(address string, client blockchain.EVMClient) error { - a := common.HexToAddress(address) - consumer, err := vrf_consumer_v2.NewVRFConsumerV2(a, client.(*blockchain.EthereumClient).Client) +func (v *EthereumVRFConsumerV2) LoadExistingConsumer(seth *seth.Client, address common.Address) error { + abi, err := vrf_consumer_v2.VRFConsumerV2MetaData.GetAbi() if err != nil { - return err + return fmt.Errorf("failed to get VRFConsumerV2 ABI: %w", err) + } + seth.ContractStore.AddABI("VRFConsumerV2", *abi) + seth.ContractStore.AddBIN("VRFConsumerV2", common.FromHex(vrf_consumer_v2.VRFConsumerV2MetaData.Bin)) + + contract, err := vrf_consumer_v2.NewVRFConsumerV2(address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return fmt.Errorf("failed to instantiate VRFConsumerV2 instance: %w", err) } - v.client = client - v.consumer = consumer - v.address = &a + + v.client = seth + v.consumer = contract + v.address = address + return nil } // CreateFundedSubscription create funded subscription for VRFv2 randomness func (v *EthereumVRFConsumerV2) CreateFundedSubscription(funds *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.CreateSubscriptionAndFund(opts, funds) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.consumer.CreateSubscriptionAndFund(v.client.NewTXOpts(), funds)) + return err } // TopUpSubscriptionFunds add funds to a VRFv2 subscription func (v *EthereumVRFConsumerV2) TopUpSubscriptionFunds(funds *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.TopUpSubscription(opts, funds) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.consumer.TopUpSubscription(v.client.NewTXOpts(), funds)) + return err } func (v *EthereumVRFConsumerV2) Address() string { @@ -803,7 +760,7 @@ func (v *EthereumVRFv2Consumer) Address() string { // CurrentSubscription get current VRFv2 subscription func (v *EthereumVRFConsumerV2) CurrentSubscription() (uint64, error) { return v.consumer.SSubId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: context.Background(), }) } @@ -811,28 +768,18 @@ func (v *EthereumVRFConsumerV2) CurrentSubscription() (uint64, error) { // GasAvailable get available gas after randomness fulfilled func (v *EthereumVRFConsumerV2) GasAvailable() (*big.Int, error) { return v.consumer.SGasAvailable(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: context.Background(), }) } -func (v *EthereumVRFConsumerV2) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ - To: v.address, - }) - if err != nil { - return err - } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +func (v *EthereumVRFConsumerV2) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") } // RequestRandomness request VRFv2 random words func (v *EthereumVRFConsumerV2) RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.RequestRandomness(opts, hash, subID, confs, gasLimit, numWords) + _, err := v.client.Decode(v.consumer.RequestRandomness(v.client.NewTXOpts(), hash, subID, confs, gasLimit, numWords)) if err != nil { return err } @@ -843,16 +790,12 @@ func (v *EthereumVRFConsumerV2) RequestRandomness(hash [32]byte, subID uint64, c Interface("KeyHash", hex.EncodeToString(hash[:])). Interface("Consumer Contract", v.address). Msg("RequestRandomness called") - return v.client.ProcessTransaction(tx) + return nil } // RequestRandomness request VRFv2 random words func (v *EthereumVRFv2Consumer) RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.RequestRandomWords(opts, subID, gasLimit, confs, numWords, hash) + _, err := v.client.Decode(v.consumer.RequestRandomWords(v.client.NewTXOpts(), subID, gasLimit, confs, numWords, hash)) if err != nil { return err } @@ -863,13 +806,13 @@ func (v *EthereumVRFv2Consumer) RequestRandomness(hash [32]byte, subID uint64, c Interface("KeyHash", hex.EncodeToString(hash[:])). Interface("Consumer Contract", v.address). Msg("RequestRandomness called") - return v.client.ProcessTransaction(tx) + return nil } // RandomnessOutput get VRFv2 randomness output (word) func (v *EthereumVRFConsumerV2) RandomnessOutput(ctx context.Context, arg0 *big.Int) (*big.Int, error) { return v.consumer.SRandomWords(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, arg0) } @@ -887,15 +830,24 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.RequestRandomWords(opts, subID, requestConfirmations, keyHash, callbackGasLimit, numWords, requestCount) + return v.RequestRandomnessFromKey(coordinator, keyHash, subID, requestConfirmations, callbackGasLimit, numWords, requestCount, 0) +} + +func (v *EthereumVRFv2LoadTestConsumer) RequestRandomnessFromKey( + coordinator Coordinator, + keyHash [32]byte, + subID uint64, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + keyNum int, +) (*CoordinatorRandomWordsRequested, error) { + tx, err := v.client.Decode(v.consumer.RequestRandomWords(v.client.NewTXKeyOpts(keyNum), subID, requestConfirmations, keyHash, callbackGasLimit, numWords, requestCount)) if err != nil { return nil, fmt.Errorf("RequestRandomWords failed, err: %w", err) } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -912,12 +864,8 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( subTopUpAmount *big.Int, linkAddress common.Address, ) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.RequestRandomWordsWithForceFulfill( - opts, + tx, err := v.client.Decode(v.consumer.RequestRandomWordsWithForceFulfill( + v.client.NewTXOpts(), requestConfirmations, keyHash, callbackGasLimit, @@ -925,11 +873,11 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( requestCount, subTopUpAmount, linkAddress, - ) + )) if err != nil { return nil, fmt.Errorf("RequestRandomWords failed, err: %w", err) } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -938,54 +886,47 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, requestID) } func (v *EthereumVRFv2Consumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { return v.consumer.LastRequestId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFv2LoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_load_test_with_metrics.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, requestID) } func (v *EthereumVRFv2LoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { return v.consumer.SLastRequestId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFv2LoadTestConsumer) ResetMetrics() error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.Reset(opts) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.consumer.Reset(v.client.NewTXOpts())) + return err } func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return &VRFLoadTestMetrics{}, err } fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -993,14 +934,14 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) return &VRFLoadTestMetrics{}, err } averageFulfillmentInMillions, err := v.consumer.SAverageFulfillmentInMillions(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return &VRFLoadTestMetrics{}, err } slowestFulfillment, err := v.consumer.SSlowestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -1008,7 +949,7 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) return &VRFLoadTestMetrics{}, err } fastestFulfillment, err := v.consumer.SFastestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { @@ -1034,27 +975,20 @@ func (v *EthereumVRFV2Wrapper) Address() string { } func (v *EthereumVRFV2Wrapper) SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.wrapper.SetConfig( - opts, + _, err := v.client.Decode(v.wrapper.SetConfig( + v.client.NewTXOpts(), wrapperGasOverhead, coordinatorGasOverhead, wrapperPremiumPercentage, keyHash, maxNumWords, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFV2Wrapper) GetSubID(ctx context.Context) (uint64, error) { return v.wrapper.SUBSCRIPTIONID(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } @@ -1063,24 +997,17 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) - if err != nil { - return err - } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") } func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(coordinator Coordinator, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.MakeRequests(opts, callbackGasLimit, requestConfirmations, numWords, requestCount) + tx, err := v.client.Decode(v.consumer.MakeRequests(v.client.NewTXOpts(), + callbackGasLimit, requestConfirmations, numWords, requestCount)) if err != nil { return nil, err } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -1089,35 +1016,35 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(coordinator Coo func (v *EthereumVRFV2WrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, requestID) } func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { return v.consumer.SLastRequestId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFV2WrapperLoadTestConsumer) GetWrapper(ctx context.Context) (common.Address, error) { return v.consumer.IVrfV2Wrapper(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -1125,14 +1052,14 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Co return nil, err } averageFulfillmentInMillions, err := v.consumer.SAverageFulfillmentInMillions(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } slowestFulfillment, err := v.consumer.SSlowestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -1140,7 +1067,7 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Co return nil, err } fastestFulfillment, err := v.consumer.SFastestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { @@ -1166,30 +1093,16 @@ func (v *EthereumVRFOwner) Address() string { } func (v *EthereumVRFOwner) SetAuthorizedSenders(senders []common.Address) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.vrfOwner.SetAuthorizedSenders( - opts, + _, err := v.client.Decode(v.vrfOwner.SetAuthorizedSenders( + v.client.NewTXOpts(), senders, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFOwner) AcceptVRFOwnership() error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.vrfOwner.AcceptVRFOwnership(opts) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.vrfOwner.AcceptVRFOwnership(v.client.NewTXOpts())) + return err } func (v *EthereumVRFOwner) WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) { @@ -1213,22 +1126,11 @@ func (v *EthereumVRFOwner) WaitForRandomWordsForcedEvent(requestIDs []*big.Int, } func (v *EthereumVRFOwner) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.vrfOwner.OwnerCancelSubscription( - opts, + // Do not wrap in Decode() to avoid waiting until the transaction is mined + return v.vrfOwner.OwnerCancelSubscription( + v.client.NewTXOpts(), subID, ) - if err != nil { - return nil, err - } - return tx, v.client.ProcessTransaction(tx) -} - -func (v *EthereumVRFCoordinatorTestV2) Address() string { - return v.address.Hex() } func (v *EthereumVRFMockETHLINKFeed) Address() string { @@ -1237,7 +1139,7 @@ func (v *EthereumVRFMockETHLINKFeed) Address() string { func (v *EthereumVRFMockETHLINKFeed) LatestRoundData() (*big.Int, error) { data, err := v.feed.LatestRoundData(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: context.Background(), }) if err != nil { @@ -1248,7 +1150,7 @@ func (v *EthereumVRFMockETHLINKFeed) LatestRoundData() (*big.Int, error) { func (v *EthereumVRFMockETHLINKFeed) LatestRoundDataUpdatedAt() (*big.Int, error) { data, err := v.feed.LatestRoundData(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: context.Background(), }) if err != nil { @@ -1258,17 +1160,6 @@ func (v *EthereumVRFMockETHLINKFeed) LatestRoundDataUpdatedAt() (*big.Int, error } func (v *EthereumVRFMockETHLINKFeed) SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.feed.SetBlockTimestampDeduction(opts, blockTimestampDeduction) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) -} - -func (v *EthereumBatchVRFCoordinatorV2) Address() string { - return v.address.Hex() + _, err := v.client.Decode(v.feed.SetBlockTimestampDeduction(v.client.NewTXOpts(), blockTimestampDeduction)) + return err } diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 3755b78f75b..16f2ec203e7 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -6,13 +6,13 @@ import ( "math/big" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/montanaflynn/stats" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" @@ -23,39 +23,39 @@ import ( ) type EthereumVRFCoordinatorV2_5 struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client coordinator vrf_coordinator_v2_5.VRFCoordinatorV25Interface } type EthereumBatchVRFCoordinatorV2Plus struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client batchCoordinator *batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2Plus } type EthereumVRFCoordinatorV2PlusUpgradedVersion struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client coordinator *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersion } // EthereumVRFv2PlusLoadTestConsumer represents VRFv2Plus consumer contract for performing Load Tests type EthereumVRFv2PlusLoadTestConsumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetrics } type EthereumVRFV2PlusWrapperLoadTestConsumer struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client consumer *vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumer } type EthereumVRFV2PlusWrapper struct { - address *common.Address - client blockchain.EVMClient + address common.Address + client *seth.Client wrapper *vrfv2plus_wrapper.VRFV2PlusWrapper } @@ -76,12 +76,8 @@ func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, fulfillmentFlatFeeNativePPM uint32, fulfillmentFlatFeeLinkDiscountPPM uint32, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.wrapper.SetConfig( - opts, + _, err := v.client.Decode(v.wrapper.SetConfig( + v.client.NewTXOpts(), wrapperGasOverhead, coordinatorGasOverheadNative, coordinatorGasOverheadLink, @@ -94,60 +90,79 @@ func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, fallbackWeiPerUnitLink, fulfillmentFlatFeeNativePPM, fulfillmentFlatFeeLinkDiscountPPM, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFV2PlusWrapper) GetSubID(ctx context.Context) (*big.Int, error) { return v.wrapper.SUBSCRIPTIONID(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFV2PlusWrapper) Coordinator(ctx context.Context) (common.Address, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } return v.wrapper.SVrfCoordinator(opts) } // DeployVRFCoordinatorV2_5 deploys VRFV2_5 coordinator contract -func (e *EthereumContractDeployer) DeployVRFCoordinatorV2_5(bhsAddr string) (VRFCoordinatorV2_5, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2Plus", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_v2_5.DeployVRFCoordinatorV25(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(bhsAddr)) - }) +func DeployVRFCoordinatorV2_5(seth *seth.Client, bhsAddr string) (VRFCoordinatorV2_5, error) { + abi, err := vrf_coordinator_v2_5.VRFCoordinatorV25MetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2_5{}, fmt.Errorf("failed to get VRFCoordinatorV2Plus ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorV2Plus", + *abi, + common.FromHex(vrf_coordinator_v2_5.VRFCoordinatorV25MetaData.Bin), + common.HexToAddress(bhsAddr)) + if err != nil { + return &EthereumVRFCoordinatorV2_5{}, fmt.Errorf("VRFCoordinatorV2Plus instance deployment have failed: %w", err) + } + + contract, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinatorV2_5{}, fmt.Errorf("failed to instantiate VRFCoordinatorV2Plus instance: %w", err) } + return &EthereumVRFCoordinatorV2_5{ - client: e.client, - coordinator: instance.(*vrf_coordinator_v2_5.VRFCoordinatorV25), - address: address, + client: seth, + coordinator: contract, + address: coordinatorDeploymentData.Address, }, err } -func (e *EthereumContractDeployer) DeployBatchVRFCoordinatorV2Plus(coordinatorAddress string) (BatchVRFCoordinatorV2Plus, error) { - address, _, instance, err := e.client.DeployContract("BatchVRFCoordinatorV2Plus", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return batch_vrf_coordinator_v2plus.DeployBatchVRFCoordinatorV2Plus(auth, backend, common.HexToAddress(coordinatorAddress)) - }) +func DeployBatchVRFCoordinatorV2Plus(seth *seth.Client, coordinatorAddress string) (BatchVRFCoordinatorV2Plus, error) { + abi, err := batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2PlusMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumBatchVRFCoordinatorV2Plus{}, fmt.Errorf("failed to get BatchVRFCoordinatorV2Plus ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinatorV2Plus", + *abi, + common.FromHex(batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2PlusMetaData.Bin), + common.HexToAddress(coordinatorAddress)) + if err != nil { + return &EthereumBatchVRFCoordinatorV2Plus{}, fmt.Errorf("BatchVRFCoordinatorV2Plus instance deployment have failed: %w", err) + } + + contract, err := batch_vrf_coordinator_v2plus.NewBatchVRFCoordinatorV2Plus(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBatchVRFCoordinatorV2Plus{}, fmt.Errorf("failed to instantiate BatchVRFCoordinatorV2Plus instance: %w", err) } + return &EthereumBatchVRFCoordinatorV2Plus{ - client: e.client, - batchCoordinator: instance.(*batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2Plus), - address: address, + client: seth, + batchCoordinator: contract, + address: coordinatorDeploymentData.Address, }, err } @@ -161,7 +176,7 @@ func (v *EthereumBatchVRFCoordinatorV2Plus) Address() string { func (v *EthereumVRFCoordinatorV2_5) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } hash, err := v.coordinator.HashOfKey(opts, pubKey) @@ -173,7 +188,7 @@ func (v *EthereumVRFCoordinatorV2_5) HashOfKey(ctx context.Context, pubKey [2]*b func (v *EthereumVRFCoordinatorV2_5) GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } activeSubscriptionIds, err := v.coordinator.GetActiveSubscriptionIds(opts, startIndex, maxCount) @@ -185,7 +200,7 @@ func (v *EthereumVRFCoordinatorV2_5) GetActiveSubscriptionIds(ctx context.Contex func (v *EthereumVRFCoordinatorV2_5) PendingRequestsExist(ctx context.Context, subID *big.Int) (bool, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } pendingRequestExists, err := v.coordinator.PendingRequestExists(opts, subID) @@ -234,7 +249,7 @@ func (v *EthereumVRFCoordinatorV2_5) ParseRandomWordsFulfilled(log types.Log) (* func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID *big.Int) (Subscription, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } subscription, err := v.coordinator.GetSubscription(opts, subID) @@ -252,7 +267,7 @@ func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID func (v *EthereumVRFCoordinatorV2_5) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } totalBalance, err := v.coordinator.STotalBalance(opts) @@ -263,7 +278,7 @@ func (v *EthereumVRFCoordinatorV2_5) GetLinkTotalBalance(ctx context.Context) (* } func (v *EthereumVRFCoordinatorV2_5) GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } totalBalance, err := v.coordinator.STotalNativeBalance(opts) @@ -276,68 +291,68 @@ func (v *EthereumVRFCoordinatorV2_5) GetNativeTokenTotalBalance(ctx context.Cont // OwnerCancelSubscription cancels subscription by Coordinator owner // return funds to sub owner, // does not check if pending requests for a sub exist -func (v *EthereumVRFCoordinatorV2_5) OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.coordinator.OwnerCancelSubscription( - opts, +func (v *EthereumVRFCoordinatorV2_5) OwnerCancelSubscription(subID *big.Int) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) { + tx, err := v.client.Decode(v.coordinator.OwnerCancelSubscription( + v.client.NewTXOpts(), subID, - ) - if err != nil { - return nil, err + )) + if err != nil { + return nil, nil, err + } + var cancelEvent *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled + for _, log := range tx.Receipt.Logs { + for _, topic := range log.Topics { + if topic.Cmp(vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled{}.Topic()) == 0 { + cancelEvent, err = v.coordinator.ParseSubscriptionCanceled(*log) + if err != nil { + return nil, nil, fmt.Errorf("parsing SubscriptionCanceled log failed, err: %w", err) + } + } + } } - return tx, v.client.ProcessTransaction(tx) + return tx, cancelEvent, err } // CancelSubscription cancels subscription by Sub owner, // return funds to specified address, // checks if pending requests for a sub exist -func (v *EthereumVRFCoordinatorV2_5) CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.coordinator.CancelSubscription( - opts, +func (v *EthereumVRFCoordinatorV2_5) CancelSubscription(subID *big.Int, to common.Address) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) { + tx, err := v.client.Decode(v.coordinator.CancelSubscription( + v.client.NewTXOpts(), subID, to, - ) - if err != nil { - return nil, err + )) + if err != nil { + return nil, nil, err + } + var cancelEvent *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled + for _, log := range tx.Receipt.Logs { + for _, topic := range log.Topics { + if topic.Cmp(vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled{}.Topic()) == 0 { + cancelEvent, err = v.coordinator.ParseSubscriptionCanceled(*log) + if err != nil { + return nil, nil, fmt.Errorf("parsing SubscriptionCanceled log failed, err: %w", err) + } + } + } } - return tx, v.client.ProcessTransaction(tx) + return tx, cancelEvent, err } func (v *EthereumVRFCoordinatorV2_5) Withdraw(recipient common.Address) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.Withdraw( - opts, + _, err := v.client.Decode(v.coordinator.Withdraw( + v.client.NewTXOpts(), recipient, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2_5) WithdrawNative(recipient common.Address) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.WithdrawNative( - opts, + _, err := v.client.Decode(v.coordinator.WithdrawNative( + v.client.NewTXOpts(), recipient, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2_5) SetConfig( @@ -350,12 +365,8 @@ func (v *EthereumVRFCoordinatorV2_5) SetConfig( fulfillmentFlatFeeLinkDiscountPPM uint32, nativePremiumPercentage uint8, linkPremiumPercentage uint8) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.SetConfig( - opts, + _, err := v.client.Decode(v.coordinator.SetConfig( + v.client.NewTXOpts(), minimumRequestConfirmations, maxGasLimit, stalenessSeconds, @@ -365,114 +376,83 @@ func (v *EthereumVRFCoordinatorV2_5) SetConfig( fulfillmentFlatFeeLinkDiscountPPM, nativePremiumPercentage, linkPremiumPercentage, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2_5) SetLINKAndLINKNativeFeed(linkAddress string, linkNativeFeedAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.SetLINKAndLINKNativeFeed( - opts, + _, err := v.client.Decode(v.coordinator.SetLINKAndLINKNativeFeed( + v.client.NewTXOpts(), common.HexToAddress(linkAddress), common.HexToAddress(linkNativeFeedAddress), - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2_5) RegisterProvingKey( publicProvingKey [2]*big.Int, gasLaneMaxGas uint64, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterProvingKey(opts, publicProvingKey, gasLaneMaxGas) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), publicProvingKey, gasLaneMaxGas)) + return err } func (v *EthereumVRFCoordinatorV2_5) CreateSubscription() (*types.Transaction, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + tx, err := v.client.Decode(v.coordinator.CreateSubscription(v.client.NewTXOpts())) if err != nil { return nil, err } - tx, err := v.coordinator.CreateSubscription(opts) - if err != nil { - return nil, err - } - return tx, v.client.ProcessTransaction(tx) + return tx.Transaction, nil } -func (v *EthereumVRFCoordinatorV2_5) Migrate(subId *big.Int, coordinatorAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) +func (v *EthereumVRFCoordinatorV2_5) Migrate(subId *big.Int, coordinatorAddress string) (*seth.DecodedTransaction, *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) { + tx, err := v.client.Decode(v.coordinator.Migrate(v.client.NewTXOpts(), subId, common.HexToAddress(coordinatorAddress))) if err != nil { - return err + return nil, nil, err } - tx, err := v.coordinator.Migrate(opts, subId, common.HexToAddress(coordinatorAddress)) - if err != nil { - return err + var migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted + for _, log := range tx.Receipt.Logs { + for _, topic := range log.Topics { + if topic.Cmp(vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted{}.Topic()) == 0 { + migrationCompletedEvent, err = v.coordinator.ParseMigrationCompleted(*log) + if err != nil { + return nil, nil, fmt.Errorf("parsing MigrationCompleted log failed, err: %w", err) + } + } + } } - return v.client.ProcessTransaction(tx) + return tx, migrationCompletedEvent, err } func (v *EthereumVRFCoordinatorV2_5) RegisterMigratableCoordinator(migratableCoordinatorAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterMigratableCoordinator(opts, common.HexToAddress(migratableCoordinatorAddress)) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterMigratableCoordinator(v.client.NewTXOpts(), common.HexToAddress(migratableCoordinatorAddress))) + return err } func (v *EthereumVRFCoordinatorV2_5) AddConsumer(subId *big.Int, consumerAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.AddConsumer( - opts, + _, err := v.client.Decode(v.coordinator.AddConsumer( + v.client.NewTXOpts(), subId, common.HexToAddress(consumerAddress), - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2_5) FundSubscriptionWithNative(subId *big.Int, nativeTokenAmount *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } + opts := v.client.NewTXOpts() opts.Value = nativeTokenAmount - tx, err := v.coordinator.FundSubscriptionWithNative( + _, err := v.client.Decode(v.coordinator.FundSubscriptionWithNative( opts, subId, - ) + )) if err != nil { return err } - return v.client.ProcessTransaction(tx) + return nil } func (v *EthereumVRFCoordinatorV2_5) FindSubscriptionID(subID *big.Int) (*big.Int, error) { - owner := v.client.GetDefaultWallet().Address() + owner := v.client.MustGetRootKeyAddress() subscriptionIterator, err := v.coordinator.FilterSubscriptionCreated( nil, []*big.Int{subID}, @@ -488,26 +468,6 @@ func (v *EthereumVRFCoordinatorV2_5) FindSubscriptionID(subID *big.Int) (*big.In return subscriptionIterator.Event.SubId, nil } -func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) { - eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated) - subscription, err := v.coordinator.WatchSubscriptionCreated(nil, eventsChannel, nil) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for SubscriptionCreated event") - case sub := <-eventsChannel: - return sub, nil - } - } -} - func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCanceledEvent(subID *big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled, error) { eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCanceled) subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, []*big.Int{subID}) @@ -586,29 +546,10 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForConfigSetEvent(timeout time.Duration } } -func (v *EthereumVRFCoordinatorV2_5) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) { - eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted) - subscription, err := v.coordinator.WatchMigrationCompleted(nil, eventsChannel) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for MigrationCompleted event") - case migrationCompletedEvent := <-eventsChannel: - return migrationCompletedEvent, nil - } - } -} - func (v *EthereumVRFv2PlusLoadTestConsumer) Address() string { return v.address.Hex() } + func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness( coordinator Coordinator, keyHash [32]byte, subID *big.Int, @@ -618,15 +559,24 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness( numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.RequestRandomWords(opts, subID, requestConfirmations, keyHash, callbackGasLimit, nativePayment, numWords, requestCount) + return v.RequestRandomnessFromKey(coordinator, keyHash, subID, requestConfirmations, callbackGasLimit, nativePayment, numWords, requestCount, 0) +} + +func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomnessFromKey( + coordinator Coordinator, + keyHash [32]byte, subID *big.Int, + requestConfirmations uint16, + callbackGasLimit uint32, + nativePayment bool, + numWords uint32, + requestCount uint16, + keyNum int, +) (*CoordinatorRandomWordsRequested, error) { + tx, err := v.client.Decode(v.consumer.RequestRandomWords(v.client.NewTXKeyOpts(keyNum), subID, requestConfirmations, keyHash, callbackGasLimit, nativePayment, numWords, requestCount)) if err != nil { return nil, err } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -634,47 +584,40 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness( } func (v *EthereumVRFv2PlusLoadTestConsumer) ResetMetrics() error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.consumer.Reset(opts) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.consumer.Reset(v.client.NewTXOpts())) + return err } func (v *EthereumVRFv2PlusLoadTestConsumer) GetCoordinator(ctx context.Context) (common.Address, error) { return v.consumer.SVrfCoordinator(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFv2PlusLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2plus_load_test_with_metrics.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, requestID) } func (v *EthereumVRFv2PlusLoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { return v.consumer.SLastRequestId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -682,14 +625,14 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte return nil, err } averageFulfillmentInMillions, err := v.consumer.SAverageResponseTimeInBlocksMillions(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } slowestFulfillment, err := v.consumer.SSlowestResponseTimeInBlocks(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -697,28 +640,28 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte return nil, err } fastestFulfillment, err := v.consumer.SFastestResponseTimeInBlocks(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } averageResponseTimeInSeconds, err := v.consumer.SAverageResponseTimeInSecondsMillions(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } slowestResponseTimeInSeconds, err := v.consumer.SSlowestResponseTimeInSeconds(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } fastestResponseTimeInSeconds, err := v.consumer.SFastestResponseTimeInSeconds(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { @@ -727,7 +670,7 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte var responseTimesInBlocks []uint32 for { currentResponseTimesInBlocks, err := v.consumer.GetRequestBlockTimes(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, big.NewInt(int64(len(responseTimesInBlocks))), big.NewInt(1000)) if err != nil { @@ -770,20 +713,31 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte }, nil } -func (e *EthereumContractDeployer) DeployVRFCoordinatorV2PlusUpgradedVersion(bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) { - address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2PlusUpgradedVersion", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_v2plus_upgraded_version.DeployVRFCoordinatorV2PlusUpgradedVersion(auth, backend, common.HexToAddress(bhsAddr)) - }) +func DeployVRFCoordinatorV2PlusUpgradedVersion(client *seth.Client, bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) { + abi, err := vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFCoordinatorV2PlusUpgradedVersion{}, fmt.Errorf("failed to get VRFCoordinatorV2PlusUpgradedVersion ABI: %w", err) } + + data, err := client.DeployContract( + client.NewTXOpts(), + "VRFCoordinatorV2PlusUpgradedVersion", + *abi, + common.FromHex(vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMetaData.Bin), + common.HexToAddress(bhsAddr)) + if err != nil { + return &EthereumVRFCoordinatorV2PlusUpgradedVersion{}, fmt.Errorf("VRFCoordinatorV2PlusUpgradedVersion instance deployment have failed: %w", err) + } + + contract, err := vrf_v2plus_upgraded_version.NewVRFCoordinatorV2PlusUpgradedVersion(data.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumVRFCoordinatorV2PlusUpgradedVersion{}, fmt.Errorf("failed to instantiate VRFCoordinatorV2PlusUpgradedVersion instance: %w", err) + } + return &EthereumVRFCoordinatorV2PlusUpgradedVersion{ - client: e.client, - coordinator: instance.(*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersion), - address: address, + client: client, + coordinator: contract, + address: data.Address, }, err } @@ -793,7 +747,7 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) Address() string { func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } hash, err := v.coordinator.HashOfKey(opts, pubKey) @@ -805,7 +759,7 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) HashOfKey(ctx context.Cont func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } activeSubscriptionIds, err := v.coordinator.GetActiveSubscriptionIds(opts, startIndex, maxCount) @@ -817,7 +771,7 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetActiveSubscriptionIds(c func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetSubscription(ctx context.Context, subID *big.Int) (vrf_v2plus_upgraded_version.GetSubscription, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } subscription, err := v.coordinator.GetSubscription(opts, subID) @@ -838,12 +792,8 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetConfig( nativePremiumPercentage uint8, linkPremiumPercentage uint8, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.SetConfig( - opts, + _, err := v.client.Decode(v.coordinator.SetConfig( + v.client.NewTXOpts(), minimumRequestConfirmations, maxGasLimit, stalenessSeconds, @@ -853,59 +803,35 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetConfig( fulfillmentFlatFeeLinkDiscountPPM, nativePremiumPercentage, linkPremiumPercentage, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetLINKAndLINKNativeFeed(linkAddress string, linkNativeFeedAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.SetLINKAndLINKNativeFeed( - opts, + _, err := v.client.Decode(v.coordinator.SetLINKAndLINKNativeFeed( + v.client.NewTXOpts(), common.HexToAddress(linkAddress), common.HexToAddress(linkNativeFeedAddress), - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) RegisterProvingKey( publicProvingKey [2]*big.Int, gasLaneMaxGas uint64, ) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterProvingKey(opts, publicProvingKey, gasLaneMaxGas) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), publicProvingKey, gasLaneMaxGas)) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) CreateSubscription() error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.CreateSubscription(opts) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.CreateSubscription(v.client.NewTXOpts())) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } totalBalance, err := v.coordinator.STotalBalance(opts) @@ -916,7 +842,7 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetLinkTotalBalance(ctx co } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, } totalBalance, err := v.coordinator.STotalNativeBalance(opts) @@ -927,63 +853,36 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) GetNativeTokenTotalBalance } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) Migrate(subId *big.Int, coordinatorAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.Migrate(opts, subId, common.HexToAddress(coordinatorAddress)) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.Migrate(v.client.NewTXOpts(), subId, common.HexToAddress(coordinatorAddress))) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) RegisterMigratableCoordinator(migratableCoordinatorAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.RegisterMigratableCoordinator(opts, common.HexToAddress(migratableCoordinatorAddress)) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + _, err := v.client.Decode(v.coordinator.RegisterMigratableCoordinator(v.client.NewTXOpts(), common.HexToAddress(migratableCoordinatorAddress))) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) AddConsumer(subId *big.Int, consumerAddress string) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.coordinator.AddConsumer( - opts, + _, err := v.client.Decode(v.coordinator.AddConsumer( + v.client.NewTXOpts(), subId, common.HexToAddress(consumerAddress), - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) FundSubscriptionWithNative(subId *big.Int, nativeTokenAmount *big.Int) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } + opts := v.client.NewTXOpts() opts.Value = nativeTokenAmount - tx, err := v.coordinator.FundSubscriptionWithNative( + _, err := v.client.Decode(v.coordinator.FundSubscriptionWithNative( opts, subId, - ) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) + )) + return err } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) FindSubscriptionID() (*big.Int, error) { - owner := v.client.GetDefaultWallet().Address() + owner := v.client.MustGetRootKeyAddress() subscriptionIterator, err := v.coordinator.FilterSubscriptionCreated( nil, nil, @@ -1028,26 +927,6 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForRandomWordsFulfille } } -func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMigrationCompleted, error) { - eventsChannel := make(chan *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMigrationCompleted) - subscription, err := v.coordinator.WatchMigrationCompleted(nil, eventsChannel) - if err != nil { - return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for MigrationCompleted event") - case migrationCompletedEvent := <-eventsChannel: - return migrationCompletedEvent, nil - } - } -} - func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) { randomWordsRequested, err := v.coordinator.ParseRandomWordsRequested(log) if err != nil { @@ -1114,54 +993,88 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForConfigSetEvent(time } } -func (e *EthereumContractDeployer) DeployVRFv2PlusLoadTestConsumer(coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFV2PlusLoadTestWithMetrics", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_v2plus_load_test_with_metrics.DeployVRFV2PlusLoadTestWithMetrics(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) - }) +func DeployVRFv2PlusLoadTestConsumer(seth *seth.Client, coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) { + abi, err := vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetricsMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFv2PlusLoadTestConsumer{}, fmt.Errorf("failed to get VRFV2PlusLoadTestWithMetrics ABI: %w", err) } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFV2PlusLoadTestWithMetrics", + *abi, + common.FromHex(vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetricsMetaData.Bin), + common.HexToAddress(coordinatorAddr)) + if err != nil { + return &EthereumVRFv2PlusLoadTestConsumer{}, fmt.Errorf("VRFV2PlusLoadTestWithMetrics instance deployment have failed: %w", err) + } + + contract, err := vrf_v2plus_load_test_with_metrics.NewVRFV2PlusLoadTestWithMetrics(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFv2PlusLoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2PlusLoadTestWithMetrics instance: %w", err) + } + return &EthereumVRFv2PlusLoadTestConsumer{ - client: e.client, - consumer: instance.(*vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetrics), - address: address, + client: seth, + consumer: contract, + address: data.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string, subId *big.Int) (VRFV2PlusWrapper, error) { - address, _, instance, err := e.client.DeployContract("VRFV2PlusWrapper", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2plus_wrapper.DeployVRFV2PlusWrapper(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr), subId) - }) +func DeployVRFV2PlusWrapper(seth *seth.Client, linkAddr string, linkEthFeedAddr string, coordinatorAddr string, subId *big.Int) (VRFV2PlusWrapper, error) { + abi, err := vrfv2plus_wrapper.VRFV2PlusWrapperMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFV2PlusWrapper{}, fmt.Errorf("failed to get VRFV2PlusWrapper ABI: %w", err) } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFV2PlusWrapper", + *abi, + common.FromHex(vrfv2plus_wrapper.VRFV2PlusWrapperMetaData.Bin), + common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), + common.HexToAddress(coordinatorAddr), subId) + if err != nil { + return &EthereumVRFV2PlusWrapper{}, fmt.Errorf("VRFV2PlusWrapper instance deployment have failed: %w", err) + } + + contract, err := vrfv2plus_wrapper.NewVRFV2PlusWrapper(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFV2PlusWrapper{}, fmt.Errorf("failed to instantiate VRFV2PlusWrapper instance: %w", err) + } + return &EthereumVRFV2PlusWrapper{ - client: e.client, - wrapper: instance.(*vrfv2plus_wrapper.VRFV2PlusWrapper), - address: address, + client: seth, + wrapper: contract, + address: data.Address, }, err } -func (e *EthereumContractDeployer) DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) { - address, _, instance, err := e.client.DeployContract("VRFV2PlusWrapperLoadTestConsumer", func( - auth *bind.TransactOpts, - backend bind.ContractBackend, - ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2plus_wrapper_load_test_consumer.DeployVRFV2PlusWrapperLoadTestConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(vrfV2PlusWrapperAddr)) - }) +func DeployVRFV2PlusWrapperLoadTestConsumer(seth *seth.Client, vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) { + abi, err := vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumerMetaData.GetAbi() if err != nil { - return nil, err + return &EthereumVRFV2PlusWrapperLoadTestConsumer{}, fmt.Errorf("failed to get VRFV2PlusWrapperLoadTestConsumer ABI: %w", err) } + + data, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFV2PlusWrapperLoadTestConsumer", + *abi, + common.FromHex(vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumerMetaData.Bin), + common.HexToAddress(vrfV2PlusWrapperAddr)) + if err != nil { + return &EthereumVRFV2PlusWrapperLoadTestConsumer{}, fmt.Errorf("VRFV2PlusWrapperLoadTestConsumer instance deployment have failed: %w", err) + } + + contract, err := vrfv2plus_wrapper_load_test_consumer.NewVRFV2PlusWrapperLoadTestConsumer(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFV2PlusWrapperLoadTestConsumer{}, fmt.Errorf("failed to instantiate VRFV2PlusWrapperLoadTestConsumer instance: %w", err) + } + return &EthereumVRFV2PlusWrapperLoadTestConsumer{ - client: e.client, - consumer: instance.(*vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumer), - address: address, + client: seth, + consumer: contract, + address: data.Address, }, err } @@ -1169,14 +1082,8 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ - To: v.address, - }) - if err != nil { - return err - } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomness( @@ -1186,15 +1093,11 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomness( numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.MakeRequests(opts, callbackGasLimit, requestConfirmations, numWords, requestCount) + tx, err := v.client.Decode(v.consumer.MakeRequests(v.client.NewTXOpts(), callbackGasLimit, requestConfirmations, numWords, requestCount)) if err != nil { return nil, err } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -1208,15 +1111,11 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomnessNative( numWords uint32, requestCount uint16, ) (*CoordinatorRandomWordsRequested, error) { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return nil, err - } - tx, err := v.consumer.MakeRequestsNative(opts, callbackGasLimit, requestConfirmations, numWords, requestCount) + tx, err := v.client.Decode(v.consumer.MakeRequestsNative(v.client.NewTXOpts(), callbackGasLimit, requestConfirmations, numWords, requestCount)) if err != nil { return nil, err } - randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, tx.Receipt.Logs) if err != nil { return nil, err } @@ -1225,35 +1124,35 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomnessNative( func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }, requestID) } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { return v.consumer.SLastRequestId(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetWrapper(ctx context.Context) (common.Address, error) { return v.consumer.IVrfV2PlusWrapper(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -1261,14 +1160,14 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetLoadTestMetrics(ctx contex return nil, err } averageFulfillmentInMillions, err := v.consumer.SAverageFulfillmentInMillions(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { return nil, err } slowestFulfillment, err := v.consumer.SSlowestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) @@ -1276,7 +1175,7 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetLoadTestMetrics(ctx contex return nil, err } fastestFulfillment, err := v.consumer.SFastestFulfillment(&bind.CallOpts{ - From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + From: v.client.MustGetRootKeyAddress(), Context: ctx, }) if err != nil { diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index f874b223e31..5a1649155cb 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logstream" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/runid" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -426,6 +427,11 @@ func (te *CLClusterTestEnv) GetSethClient(chainId int64) (*seth.Client, error) { return nil, fmt.Errorf("no Seth client available for chain ID %d", chainId) } +func (te *CLClusterTestEnv) GetSethClientForSelectedNetwork() (*seth.Client, error) { + n := networks.MustGetSelectedNetworkConfig(te.TestConfig.GetNetworkConfig())[0] + return te.GetSethClient(n.ChainID) +} + func (te *CLClusterTestEnv) GetRpcProvider(chainId int64) (*test_env.RpcProvider, error) { if rpc, ok := te.rpcProviders[chainId]; ok { return rpc, nil diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 707f7d9222b..cdb310114ee 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -420,7 +420,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.hasSeth { - seth, err := actions_seth.GetChainClientWithConfigFunction(b.testConfig, networkConfig, actions_seth.OneEphemeralKeysLiveTestnetAutoFixFn) + seth, err := actions_seth.GetChainClient(b.testConfig, networkConfig) if err != nil { return nil, err } @@ -513,7 +513,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if b.hasSeth { b.te.sethClients = make(map[int64]*seth.Client) - seth, err := actions_seth.GetChainClientWithConfigFunction(b.testConfig, networkConfig, actions_seth.OneEphemeralKeysLiveTestnetAutoFixFn) + seth, err := actions_seth.GetChainClient(b.testConfig, networkConfig) if err != nil { return nil, err } diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index d15ee18d451..a962dbfd6bb 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -4,11 +4,13 @@ import ( "math/rand" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/smartcontractkit/wasp" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" vrfv2_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) type BHSTestGun struct { @@ -17,6 +19,7 @@ type BHSTestGun struct { keyHash [32]byte testConfig *vrfv2_config.Config logger zerolog.Logger + sethClient *seth.Client } func NewBHSTestGun( @@ -25,6 +28,7 @@ func NewBHSTestGun( subIDs []uint64, testConfig *vrfv2_config.Config, logger zerolog.Logger, + sethClient *seth.Client, ) *BHSTestGun { return &BHSTestGun{ contracts: contracts, @@ -32,6 +36,7 @@ func NewBHSTestGun( keyHash: keyHash, testConfig: testConfig, logger: logger, + sethClient: sethClient, } } @@ -48,6 +53,7 @@ func (m *BHSTestGun) Call(_ *wasp.Generator) *wasp.Response { *m.testConfig.General.NumberOfWords, *m.testConfig.General.RandomnessRequestCountPerRequest, *m.testConfig.General.RandomnessRequestCountPerRequestDeviation, + utils.AvailableSethKeyNum(m.sethClient), ) //todo - might need to store randRequestBlockNumber and blockhash to verify that it was stored in BHS contract at the end of the test if err != nil { @@ -62,6 +68,7 @@ type SingleHashGun struct { subIDs []uint64 testConfig *vrfv2_config.Config logger zerolog.Logger + sethClient *seth.Client } func NewSingleHashGun( @@ -70,6 +77,7 @@ func NewSingleHashGun( subIDs []uint64, testConfig *vrfv2_config.Config, logger zerolog.Logger, + sethClient *seth.Client, ) *SingleHashGun { return &SingleHashGun{ contracts: contracts, @@ -77,6 +85,7 @@ func NewSingleHashGun( subIDs: subIDs, testConfig: testConfig, logger: logger, + sethClient: sethClient, } } @@ -101,6 +110,7 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { randomnessRequestCountPerRequest, *vrfv2Config.RandomnessRequestCountPerRequestDeviation, vrfv2Config.RandomWordsFulfilledEventTimeout.Duration, + utils.AvailableSethKeyNum(m.sethClient), ) if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index a62e4cdd552..04234a904ae 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -38,7 +39,6 @@ func TestVRFV2Performance(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -57,7 +57,11 @@ func TestVRFV2Performance(t *testing.T) { l.Error().Err(err).Msg(ErrLokiClient) return } - chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + chainID := network.ChainID + sethClient, err := actions_seth.GetChainClient(testConfig, network) + require.NoError(t, err, "Error creating seth client") + updatedLabels := UpdateLabels(labels, t) l.Info(). @@ -72,17 +76,16 @@ func TestVRFV2Performance(t *testing.T) { cleanupFn := func() { teardown(t, vrfContracts.VRFV2Consumers[0], lc, updatedLabels, testReporter, testType, &testConfig) - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") + require.NoError(t, err, "Getting Seth client shouldn't fail") - if evmClient.NetworkSimulated() { + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -102,9 +105,6 @@ func TestVRFV2Performance(t *testing.T) { testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - var consumers []contracts.VRFv2LoadTestConsumer subIDs, consumers, err := vrfv2.SetupSubsAndConsumersForExistingEnv( testEnv, @@ -126,7 +126,6 @@ func TestVRFV2Performance(t *testing.T) { l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") vrfContracts.VRFV2Consumers = consumers - defaultWalletAddress = evmClient.GetDefaultWallet().Address() // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2 performance test", func(t *testing.T) { @@ -146,6 +145,7 @@ func TestVRFV2Performance(t *testing.T) { subIDs, vrfv2Config, l, + sethClient, ), Labels: labels, LokiConfig: lokiConfig, @@ -180,7 +180,6 @@ func TestVRFV2BHSPerformance(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -212,21 +211,20 @@ func TestVRFV2BHSPerformance(t *testing.T) { Msg("Performance Test Configuration") chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + sethClient, err := testEnv.GetSethClient(chainID) cleanupFn := func() { teardown(t, vrfContracts.VRFV2Consumers[0], lc, updatedLabels, testReporter, testType, &testConfig) - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - - if evmClient.NetworkSimulated() { + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -246,10 +244,6 @@ func TestVRFV2BHSPerformance(t *testing.T) { testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - - defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("vrfv2 and bhs performance test", func(t *testing.T) { configCopy := testConfig.MustCopy().(tc.TestConfig) //Underfund Subscription @@ -289,6 +283,7 @@ func TestVRFV2BHSPerformance(t *testing.T) { underfundedSubIDs, configCopy.VRFv2, l, + sethClient, ), Labels: labels, LokiConfig: lokiConfig, @@ -307,9 +302,18 @@ func TestVRFV2BHSPerformance(t *testing.T) { var wgBlockNumberTobe sync.WaitGroup wgBlockNumberTobe.Add(1) //Wait at least 256 blocks - latestBlockNumber, err := evmClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "error getting latest block number") - _, err = actions.WaitForBlockNumberToBe(latestBlockNumber+uint64(256), evmClient, &wgBlockNumberTobe, configCopy.VRFv2.General.WaitFor256BlocksTimeout.Duration, t) + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + latestBlockNumber, err := sethClient.Client.BlockNumber(testcontext.Get(t)) + require.NoError(t, err) + _, err = actions.WaitForBlockNumberToBe( + latestBlockNumber+uint64(256), + sethClient, + &wgBlockNumberTobe, + configCopy.VRFv2.General.WaitFor256BlocksTimeout.Duration, + t, + l, + ) wgBlockNumberTobe.Wait() require.NoError(t, err, "error waiting for block number to be") @@ -324,8 +328,6 @@ func TestVRFV2BHSPerformance(t *testing.T) { Uints64("SubIDs", subIDsString). Msg("Funding Subscriptions with Link and Native Tokens") err = vrfv2.FundSubscriptions( - testEnv, - chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 6879fbe32dc..c95e7161322 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -6,11 +6,13 @@ import ( "math/rand" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/smartcontractkit/wasp" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) type BHSTestGun struct { @@ -19,6 +21,7 @@ type BHSTestGun struct { subIDs []*big.Int testConfig *vrfv2plus_config.Config logger zerolog.Logger + sethClient *seth.Client } func NewBHSTestGun( @@ -27,6 +30,7 @@ func NewBHSTestGun( subIDs []*big.Int, testConfig *vrfv2plus_config.Config, logger zerolog.Logger, + sethClient *seth.Client, ) *BHSTestGun { return &BHSTestGun{ contracts: contracts, @@ -34,6 +38,7 @@ func NewBHSTestGun( keyHash: keyHash, testConfig: testConfig, logger: logger, + sethClient: sethClient, } } @@ -54,6 +59,7 @@ func (m *BHSTestGun) Call(_ *wasp.Generator) *wasp.Response { billingType, vrfv2PlusConfig, m.logger, + utils.AvailableSethKeyNum(m.sethClient), ) //todo - might need to store randRequestBlockNumber and blockhash to verify that it was stored in BHS contract at the end of the test if err != nil { @@ -69,6 +75,7 @@ type SingleHashGun struct { subIDs []*big.Int testConfig *vrfv2plus_config.Config logger zerolog.Logger + sethClient *seth.Client } func NewSingleHashGun( @@ -77,6 +84,7 @@ func NewSingleHashGun( subIDs []*big.Int, testConfig *vrfv2plus_config.Config, logger zerolog.Logger, + sethClient *seth.Client, ) *SingleHashGun { return &SingleHashGun{ contracts: contracts, @@ -84,6 +92,7 @@ func NewSingleHashGun( subIDs: subIDs, testConfig: testConfig, logger: logger, + sethClient: sethClient, } } @@ -109,6 +118,7 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { billingType, vrfv2PlusConfig, m.logger, + utils.AvailableSethKeyNum(m.sethClient), ) if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 2496e2b692b..18ad008651f 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -37,7 +38,6 @@ func TestVRFV2PlusPerformance(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -56,7 +56,10 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Error().Err(err).Msg(ErrLokiClient) return } - chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + chainID := network.ChainID + sethClient, err := actions_seth.GetChainClient(testConfig, network) + require.NoError(t, err, "Error creating seth client") updatedLabels := UpdateLabels(labels, t) l.Info(). @@ -71,18 +74,15 @@ func TestVRFV2PlusPerformance(t *testing.T) { cleanupFn := func() { teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, testType, &testConfig) - - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - - if evmClient.NetworkSimulated() { + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*testConfig.VRFv2Plus.General.UseExistingEnv { @@ -100,11 +100,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - var consumers []contracts.VRFv2PlusLoadTestConsumer subIDs, consumers, err := vrfv2plus.SetupSubsAndConsumersForExistingEnv( + testcontext.Get(t), testEnv, chainID, vrfContracts.CoordinatorV2Plus, @@ -124,7 +122,6 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Info().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") vrfContracts.VRFV2PlusConsumer = consumers - defaultWalletAddress = evmClient.GetDefaultWallet().Address() // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2plus performance test", func(t *testing.T) { @@ -145,6 +142,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { subIDs, vrfv2PlusConfig, l, + sethClient, ), Labels: labels, LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), @@ -179,7 +177,6 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -210,22 +207,22 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { Bool("UseExistingEnv", *vrfv2PlusConfig.General.UseExistingEnv). Msg("Performance Test Configuration") - chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + chainID := network.ChainID + sethClient, err := actions_seth.GetChainClientWithConfigFunction(testConfig, network, actions_seth.OneEphemeralKeysLiveTestnetCheckFn) + require.NoError(t, err, "Error creating seth client") cleanupFn := func() { teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, testType, &testConfig) - - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - - if evmClient.NetworkSimulated() { + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*testConfig.VRFv2Plus.General.UseExistingEnv { @@ -236,18 +233,13 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { } newEnvConfig := vrfcommon.NewEnvConfig{ - NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, } testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "error getting EVM client") - - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("vrfv2plus and bhs performance test", func(t *testing.T) { configCopy := testConfig.MustCopy().(tc.TestConfig) //Underfund Subscription @@ -255,6 +247,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) underfundedSubIDs, consumers, err := vrfv2plus.SetupSubsAndConsumersForExistingEnv( + testcontext.Get(t), testEnv, chainID, vrfContracts.CoordinatorV2Plus, @@ -290,6 +283,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { underfundedSubIDs, configCopy.VRFv2Plus, l, + sethClient, ), Labels: labels, LokiConfig: lokiConfig, @@ -308,9 +302,18 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { var wgBlockNumberTobe sync.WaitGroup wgBlockNumberTobe.Add(1) //Wait at least 256 blocks - latestBlockNumber, err := evmClient.LatestBlockNumber(testcontext.Get(t)) + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + latestBlockNumber, err := sethClient.Client.BlockNumber(testcontext.Get(t)) require.NoError(t, err, "error getting latest block number") - _, err = actions.WaitForBlockNumberToBe(latestBlockNumber+uint64(256), evmClient, &wgBlockNumberTobe, configCopy.VRFv2Plus.General.WaitFor256BlocksTimeout.Duration, t) + _, err = actions.WaitForBlockNumberToBe( + latestBlockNumber+uint64(256), + sethClient, + &wgBlockNumberTobe, + configCopy.VRFv2Plus.General.WaitFor256BlocksTimeout.Duration, + t, + l, + ) wgBlockNumberTobe.Wait() require.NoError(t, err, "error waiting for block number to be") @@ -329,8 +332,6 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { Strs("SubIDs", subIDsString). Msg("Funding Subscriptions with Link and Native Tokens") err = vrfv2plus.FundSubscriptions( - testEnv, - chainID, big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 3f9a7e3649a..bf4f5804e99 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -21,11 +21,12 @@ import ( "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" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "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/testconfig" - tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/utils" ) var ocr2vrfSmokeConfig *testconfig.TestConfig @@ -34,7 +35,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.OCR2) + config, err := testconfig.GetConfig("Smoke", testconfig.OCR2) if err != nil { t.Fatal(err) } @@ -44,33 +45,30 @@ func TestOCR2VRFRedeemModel(t *testing.T) { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") + testNetwork = utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) + chainClient, err := actions_seth.GetChainClientWithConfigFunction(config, testNetwork, actions_seth.OneEphemeralKeysLiveTestnetCheckFn) + require.NoError(t, err, "Error creating seth client") + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) + err := actions_seth.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config) require.NoError(t, err, "Error tearing down environment") }) - chainClient.ParallelTransactions(true) - - linkToken, err := contractDeployer.DeployLinkTokenContract() + linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) require.NoError(t, err, "Error deploying LINK token") - mockETHLinkFeed, err := contractDeployer.DeployMockETHLINKFeed(ocr2vrf_constants.LinkEthFeedResponse) + mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( t, linkToken, mockETHLinkFeed, - contractDeployer, chainClient, nodeAddresses, chainlinkNodes, @@ -81,7 +79,6 @@ func TestOCR2VRFRedeemModel(t *testing.T) { requestID := ocr2vrf_actions.RequestAndRedeemRandomness( t, consumerContract, - chainClient, vrfBeaconContract, ocr2vrf_constants.NumberOfRandomWordsToRequest, subID, @@ -101,7 +98,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.OCR2) + config, err := testconfig.GetConfig("Smoke", testconfig.OCR2) if err != nil { t.Fatal(err) } @@ -111,33 +108,30 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { return } - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") + testNetwork = utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) + chainClient, err := actions_seth.GetChainClientWithConfigFunction(config, testNetwork, actions_seth.OneEphemeralKeysLiveTestnetCheckFn) + require.NoError(t, err, "Error creating seth client") + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) require.NoError(t, err, "Error connecting to Chainlink nodes") nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) + err := actions_seth.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config) require.NoError(t, err, "Error tearing down environment") }) - chainClient.ParallelTransactions(true) - - linkToken, err := contractDeployer.DeployLinkTokenContract() + linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) require.NoError(t, err, "Error deploying LINK token") - mockETHLinkFeed, err := contractDeployer.DeployMockETHLINKFeed(ocr2vrf_constants.LinkEthFeedResponse) + mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( t, linkToken, mockETHLinkFeed, - contractDeployer, chainClient, nodeAddresses, chainlinkNodes, @@ -147,7 +141,6 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { requestID := ocr2vrf_actions.RequestRandomnessFulfillmentAndWaitForFulfilment( t, consumerContract, - chainClient, vrfBeaconContract, ocr2vrf_constants.NumberOfRandomWordsToRequest, subID, @@ -165,7 +158,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { if ocr2vrfSmokeConfig == nil { - c, err := testconfig.GetConfig("Smoke", tc.OCR2VRF) + c, err := testconfig.GetConfig("Smoke", testconfig.OCR2VRF) if err != nil { t.Fatal(err) } diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 946a73f0e18..059325b1522 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -33,13 +33,16 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" ) +const ( + SethRootKeyIndex = 0 +) + func TestVRFv2Basic(t *testing.T) { t.Parallel() var ( testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -51,17 +54,16 @@ func TestVRFv2Basic(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -79,10 +81,9 @@ func TestVRFv2Basic(t *testing.T) { testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") t.Run("Request Randomness", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -118,6 +119,7 @@ func TestVRFv2Basic(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -173,6 +175,7 @@ func TestVRFv2Basic(t *testing.T) { *testConfig.RandomnessRequestCountPerRequest, *testConfig.RandomnessRequestCountPerRequestDeviation, testConfig.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -221,6 +224,7 @@ func TestVRFv2Basic(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -339,26 +343,24 @@ func TestVRFv2Basic(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceLinkBeforeOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) l.Info(). - Str("Returning to", defaultWalletAddress). + Str("Returning to", sethClient.MustGetRootKeyAddress().Hex()). Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfContracts.CoordinatorV2.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) + err = vrfContracts.CoordinatorV2.OracleWithdraw(sethClient.MustGetRootKeyAddress(), amountToWithdrawLink) require.NoError(t, err, "Error withdrawing LINK from coordinator to default wallet") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - - defaultWalletBalanceLinkAfterOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) require.Equal( @@ -404,34 +406,29 @@ func TestVRFv2Basic(t *testing.T) { Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfContracts.CoordinatorV2.CancelSubscription(subIDForCancelling, testWalletAddress) + cancellationTx, cancellationEvent, err := vrfContracts.CoordinatorV2.CancelSubscription(subIDForCancelling, testWalletAddress) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) - require.NoError(t, err, "error waiting for subscription canceled event") - cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) - require.NoError(t, err, "error getting tx cancellation Tx Receipt") - - txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + txGasUsed := new(big.Int).SetUint64(cancellationTx.Receipt.GasUsed) // we don't have that information for older Geth versions - if cancellationTxReceipt.EffectiveGasPrice == nil { - cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + if cancellationTx.Receipt.EffectiveGasPrice == nil { + cancellationTx.Receipt.EffectiveGasPrice = new(big.Int).SetUint64(0) } - cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTx.Receipt.EffectiveGasPrice) l.Info(). Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). - Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). - Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Str("Effective Gas Price", cancellationTx.Receipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTx.Receipt.GasUsed). Msg("Cancellation TX Receipt") l.Info(). - Str("Returned Subscription Amount Link", subscriptionCanceledEvent.Amount.String()). - Uint64("SubID", subscriptionCanceledEvent.SubId). - Str("Returned to", subscriptionCanceledEvent.To.String()). + Str("Returned Subscription Amount Link", cancellationEvent.Amount.String()). + Uint64("SubID", cancellationEvent.SubId). + Str("Returned to", cancellationEvent.To.String()). Msg("Subscription Canceled Event") - require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, cancellationEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") testWalletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) @@ -492,6 +489,7 @@ func TestVRFv2Basic(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, + 0, ) require.Error(t, err, "Error should occur while waiting for fulfilment due to low sub balance") @@ -499,7 +497,7 @@ func TestVRFv2Basic(t *testing.T) { require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfilfulled requests due to low sub balance") - walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) subscriptionForCancelling, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOwnerCancelling) @@ -509,41 +507,35 @@ func TestVRFv2Basic(t *testing.T) { l.Info(). Str("Subscription Amount Link", subBalanceLink.String()). Uint64("Returning funds from SubID", subIDForOwnerCancelling). - Str("Returning funds to", defaultWalletAddress). + Str("Returning funds to", sethClient.MustGetRootKeyAddress().Hex()). Msg("Canceling subscription and returning funds to subscription owner") // Call OwnerCancelSubscription - tx, err := vrfContracts.CoordinatorV2.OwnerCancelSubscription(subIDForOwnerCancelling) + cancellationTx, cancellationEvent, err := vrfContracts.CoordinatorV2.OwnerCancelSubscription(subIDForOwnerCancelling) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForOwnerCancelling}, time.Second*30) - require.NoError(t, err, "error waiting for subscription canceled event") - - cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) - require.NoError(t, err, "error getting tx cancellation Tx Receipt") - - txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + txGasUsed := new(big.Int).SetUint64(cancellationTx.Receipt.GasUsed) // we don't have that information for older Geth versions - if cancellationTxReceipt.EffectiveGasPrice == nil { - cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + if cancellationTx.Receipt.EffectiveGasPrice == nil { + cancellationTx.Receipt.EffectiveGasPrice = new(big.Int).SetUint64(0) } - cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTx.Receipt.EffectiveGasPrice) l.Info(). Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). - Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). - Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Str("Effective Gas Price", cancellationTx.Receipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTx.Receipt.GasUsed). Msg("Cancellation TX Receipt") l.Info(). - Str("Returned Subscription Amount Link", subscriptionCanceledEvent.Amount.String()). - Uint64("SubID", subscriptionCanceledEvent.SubId). - Str("Returned to", subscriptionCanceledEvent.To.String()). + Str("Returned Subscription Amount Link", cancellationEvent.Amount.String()). + Uint64("SubID", cancellationEvent.SubId). + Str("Returned to", cancellationEvent.To.String()). Msg("Subscription Canceled Event") - require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, cancellationEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) // Verify that subscription was deleted from Coordinator contract @@ -574,7 +566,6 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -586,17 +577,18 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { } chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID vrfv2Config := config.VRFv2 + cleanupFn := func() { - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -615,10 +607,6 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -658,11 +646,12 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - - //todo - move TransactionByHash to EVMClient in CTF - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") @@ -685,7 +674,6 @@ func TestVRFOwner(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -694,17 +682,18 @@ func TestVRFOwner(t *testing.T) { require.NoError(t, err, "Error getting config") chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID vrfv2Config := config.VRFv2 + cleanupFn := func() { - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -723,10 +712,6 @@ func TestVRFOwner(t *testing.T) { testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("Request Randomness With Force-Fulfill", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) @@ -757,9 +742,6 @@ func TestVRFOwner(t *testing.T) { ) require.NoError(t, err, "error transferring link to consumer contract") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - consumerLinkBalance, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), consumers[0].Address()) require.NoError(t, err, "error getting consumer link balance") l.Info(). @@ -769,8 +751,6 @@ func TestVRFOwner(t *testing.T) { err = vrfContracts.MockETHLINKFeed.SetBlockTimestampDeduction(big.NewInt(3)) require.NoError(t, err) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) // test and assert _, randFulfilledEvent, _, err := vrfv2.RequestRandomnessWithForceFulfillAndWaitForFulfillment( @@ -826,7 +806,6 @@ func TestVRFV2WithBHS(t *testing.T) { testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []uint64 - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -838,16 +817,16 @@ func TestVRFV2WithBHS(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -871,10 +850,6 @@ func TestVRFV2WithBHS(t *testing.T) { testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFV2 universe") - evmClient, err := testEnv.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings @@ -910,18 +885,28 @@ func TestVRFV2WithBHS(t *testing.T) { *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + SethRootKeyIndex, ) require.NoError(t, err, "error requesting randomness") - vrfcommon.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2, randomWordsRequestedEvent, false) + vrfcommon.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2, randomWordsRequestedEvent, false, 0) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber var wg sync.WaitGroup wg.Add(1) //Wait at least 256 blocks - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), evmClient, &wg, time.Second*260, t) + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + _, err = actions.WaitForBlockNumberToBe( + randRequestBlockNumber+uint64(257), + sethClient, + &wg, + time.Second*260, + t, + l, + ) wg.Wait() require.NoError(t, err) - err = vrfv2.FundSubscriptions(testEnv, chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDsForBHS) + err = vrfv2.FundSubscriptions(big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDsForBHS) require.NoError(t, err, "error funding subscriptions") randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2.WaitForRandomWordsFulfilledEvent( contracts.RandomWordsFulfilledEventFilter{ @@ -930,7 +915,7 @@ func TestVRFV2WithBHS(t *testing.T) { }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2, randomWordsFulfilledEvent, false) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2, randomWordsFulfilledEvent, false, 0) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) @@ -971,6 +956,7 @@ func TestVRFV2WithBHS(t *testing.T) { *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + SethRootKeyIndex, ) require.NoError(t, err, "error requesting randomness") @@ -979,14 +965,22 @@ func TestVRFV2WithBHS(t *testing.T) { _, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) require.Error(t, err, "error not occurred when getting blockhash for a blocknumber which was not stored in BHS contract") + sethClient, err := testEnv.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + var wg sync.WaitGroup wg.Add(1) - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*configCopy.VRFv2.General.BHSJobWaitBlocks), evmClient, &wg, time.Minute*1, t) + _, err = actions.WaitForBlockNumberToBe( + randRequestBlockNumber+uint64(*configCopy.VRFv2.General.BHSJobWaitBlocks), + sethClient, + &wg, + time.Minute*1, + t, + l, + ) wg.Wait() require.NoError(t, err, "error waiting for blocknumber to be") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) metrics, err := consumers[0].GetLoadTestMetrics(testcontext.Get(t)) require.Equal(t, 0, metrics.RequestCount.Cmp(big.NewInt(1))) require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0))) @@ -1004,7 +998,7 @@ func TestVRFV2WithBHS(t *testing.T) { require.Equal(t, strings.ToLower(vrfContracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) - bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, common.HexToHash(txHash)) + bhsStoreTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), common.HexToHash(txHash)) require.NoError(t, err, "error getting tx from hash") bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) @@ -1013,9 +1007,6 @@ func TestVRFV2WithBHS(t *testing.T) { Msg("BHS Node's Store Blockhash for Blocknumber Method TX") require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - var randRequestBlockHash [32]byte gom.Eventually(func(g gomega.Gomega) { randRequestBlockHash, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) @@ -1046,12 +1037,11 @@ func TestVRFV2NodeReorg(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { @@ -1088,9 +1078,8 @@ func TestVRFV2NodeReorg(t *testing.T) { env, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2 universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") consumers, subIDs, err := vrfv2.SetupNewConsumersAndSubs( env, @@ -1126,6 +1115,7 @@ func TestVRFV2NodeReorg(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err) @@ -1136,7 +1126,7 @@ func TestVRFV2NodeReorg(t *testing.T) { require.NoError(t, err, "error getting rpc url") //2. rewind chain by n number of blocks - basically, mimicking reorg scenario - latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), evmClient, rpcUrl, rewindChainToBlock, l) + latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), sethClient, rpcUrl, rewindChainToBlock, l) require.NoError(t, err, fmt.Sprintf("error rewinding chain to block number %d", rewindChainToBlock)) //3.1 ensure that chain is reorged and latest block number is greater than the block number when request was made @@ -1173,6 +1163,7 @@ func TestVRFV2NodeReorg(t *testing.T) { *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + SethRootKeyIndex, ) require.NoError(t, err) @@ -1183,7 +1174,7 @@ func TestVRFV2NodeReorg(t *testing.T) { require.NoError(t, err, "error getting rpc url") //3. rewind chain by n number of blocks - basically, mimicking reorg scenario - latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), evmClient, rpcUrl, rewindChainToBlockNumber, l) + latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), sethClient, rpcUrl, rewindChainToBlockNumber, l) require.NoError(t, err, fmt.Sprintf("error rewinding chain to block number %d", rewindChainToBlockNumber)) //4. ensure that chain is reorged and latest block number is less than the block number when request was made @@ -1221,12 +1212,11 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2Config.General.CancelSubsAfterTestRun { @@ -1250,9 +1240,8 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2 universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") //batchMaxGas := config.MaxGasLimit() (2.5 mill) + 400_000 = 2.9 mill //callback gas limit set by consumer = 500k @@ -1336,6 +1325,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -1362,7 +1352,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { // verify that all fulfillments should be inside one tx require.Equal(t, 1, len(batchFulfillmentTxs)) - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTXToAddress := fulfillmentTx.To().String() @@ -1374,7 +1364,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { // verify that VRF node sends fulfillments via BatchCoordinator contract require.Equal(t, vrfContracts.BatchCoordinatorV2.Address(), fulfillmentTXToAddress, "Fulfillment Tx To Address should be the BatchCoordinatorV2 Address when batch fulfillment is enabled") - fulfillmentTxReceipt, err := evmClient.GetTxReceipt(fulfillmentTx.Hash()) + fulfillmentTxReceipt, err := sethClient.Client.TransactionReceipt(testcontext.Get(t), fulfillmentTx.Hash()) require.NoError(t, err) randomWordsFulfilledLogs, err := contracts.ParseRandomWordsFulfilledLogs(vrfContracts.CoordinatorV2, fulfillmentTxReceipt.Logs) @@ -1455,6 +1445,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -1469,7 +1460,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Request/Fulfilment Stats") - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTXToAddress := fulfillmentTx.To().String() diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 6a64d08569a..8fac024f8fd 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -40,7 +40,6 @@ func TestVRFv2Plus(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -52,17 +51,17 @@ func TestVRFv2Plus(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") - if evmClient.NetworkSimulated() { + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -81,14 +80,14 @@ func TestVRFv2Plus(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") t.Run("Link Billing", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -116,6 +115,7 @@ func TestVRFv2Plus(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -146,7 +146,9 @@ func TestVRFv2Plus(t *testing.T) { var isNativeBilling = true consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, + chainID, vrfContracts.CoordinatorV2Plus, configCopy, @@ -173,6 +175,7 @@ func TestVRFv2Plus(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") require.False(t, randomWordsFulfilledEvent.OnlyPremium) @@ -201,6 +204,7 @@ func TestVRFv2Plus(t *testing.T) { var isNativeBilling = true consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -227,6 +231,7 @@ func TestVRFv2Plus(t *testing.T) { isNativeBilling, testConfig, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -243,6 +248,7 @@ func TestVRFv2Plus(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -271,6 +277,7 @@ func TestVRFv2Plus(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -282,6 +289,7 @@ func TestVRFv2Plus(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( testcontext.Get(t), + l, env, chainID, &configCopy, @@ -347,7 +355,7 @@ func TestVRFv2Plus(t *testing.T) { testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true - wrapperConsumerBalanceBeforeRequestWei, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceBeforeRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil) require.NoError(t, err, "error getting wrapper consumer balance") wrapperSubscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) @@ -377,7 +385,7 @@ func TestVRFv2Plus(t *testing.T) { expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) - wrapperConsumerBalanceAfterRequestWei, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceAfterRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) @@ -395,6 +403,7 @@ func TestVRFv2Plus(t *testing.T) { t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) _, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -414,7 +423,7 @@ func TestVRFv2Plus(t *testing.T) { testWalletAddress, err := actions.GenerateWallet() require.NoError(t, err) - testWalletBalanceNativeBeforeSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), testWalletAddress) + testWalletBalanceNativeBeforeSubCancelling, err := sethClient.Client.BalanceAt(testcontext.Get(t), testWalletAddress, nil) require.NoError(t, err) testWalletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) @@ -431,39 +440,34 @@ func TestVRFv2Plus(t *testing.T) { Str("Returning funds from SubID", subID.String()). Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, testWalletAddress) - require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subID, time.Second*30) - require.NoError(t, err, "error waiting for subscription canceled event") - - cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) - require.NoError(t, err, "error getting tx cancellation Tx Receipt") + cancellationTx, cancellationEvent, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, testWalletAddress) + require.NoError(t, err, "Error canceling subscription") - txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + txGasUsed := new(big.Int).SetUint64(cancellationTx.Receipt.GasUsed) // we don't have that information for older Geth versions - if cancellationTxReceipt.EffectiveGasPrice == nil { - cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + if cancellationTx.Receipt.EffectiveGasPrice == nil { + cancellationTx.Receipt.EffectiveGasPrice = new(big.Int).SetUint64(0) } - cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTx.Receipt.EffectiveGasPrice) l.Info(). Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). - Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). - Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Str("Effective Gas Price", cancellationTx.Receipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTx.Receipt.GasUsed). Msg("Cancellation TX Receipt") l.Info(). - Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). - Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). - Str("SubID", subscriptionCanceledEvent.SubId.String()). - Str("Returned to", subscriptionCanceledEvent.To.String()). + Str("Returned Subscription Amount Native", cancellationEvent.AmountLink.String()). + Str("Returned Subscription Amount Link", cancellationEvent.AmountLink.String()). + Str("SubID", cancellationEvent.SubId.String()). + Str("Returned to", cancellationEvent.To.String()). Msg("Subscription Canceled Event") - require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") - require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceNative, cancellationEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, cancellationEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - testWalletBalanceNativeAfterSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), testWalletAddress) + testWalletBalanceNativeAfterSubCancelling, err := sethClient.Client.BalanceAt(testcontext.Get(t), testWalletAddress, nil) require.NoError(t, err) testWalletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) @@ -503,6 +507,7 @@ func TestVRFv2Plus(t *testing.T) { testConfig.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -536,6 +541,7 @@ func TestVRFv2Plus(t *testing.T) { false, configCopy.VRFv2Plus.General, l, + 0, ) require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") @@ -548,6 +554,7 @@ func TestVRFv2Plus(t *testing.T) { true, configCopy.VRFv2Plus.General, l, + 0, ) require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") @@ -556,10 +563,10 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") - walletBalanceNativeBeforeSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeBeforeSubCancelling, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), nil) require.NoError(t, err) - walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) subscriptionForCancelling, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) @@ -571,44 +578,39 @@ func TestVRFv2Plus(t *testing.T) { Str("Subscription Amount Native", subBalanceNative.String()). Str("Subscription Amount Link", subBalanceLink.String()). Str("Returning funds from SubID", subID.String()). - Str("Returning funds to", defaultWalletAddress). + Str("Returning funds to", sethClient.MustGetRootKeyAddress().Hex()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfContracts.CoordinatorV2Plus.OwnerCancelSubscription(subID) - require.NoError(t, err, "Error canceling subscription") - - subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subID, time.Second*30) - require.NoError(t, err, "error waiting for subscription canceled event") - cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) - require.NoError(t, err, "error getting tx cancellation Tx Receipt") + cancellationTx, cancellationEvent, err := vrfContracts.CoordinatorV2Plus.OwnerCancelSubscription(subID) + require.NoError(t, err, "Error canceling subscription") - txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + txGasUsed := new(big.Int).SetUint64(cancellationTx.Receipt.GasUsed) // we don't have that information for older Geth versions - if cancellationTxReceipt.EffectiveGasPrice == nil { - cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + if cancellationTx.Receipt.EffectiveGasPrice == nil { + cancellationTx.Receipt.EffectiveGasPrice = new(big.Int).SetUint64(0) } - cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTx.Receipt.EffectiveGasPrice) l.Info(). Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). - Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). - Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Str("Effective Gas Price", cancellationTx.Receipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTx.Receipt.GasUsed). Msg("Cancellation TX Receipt") l.Info(). - Str("Returned Subscription Amount Native", subscriptionCanceledEvent.AmountNative.String()). - Str("Returned Subscription Amount Link", subscriptionCanceledEvent.AmountLink.String()). - Str("SubID", subscriptionCanceledEvent.SubId.String()). - Str("Returned to", subscriptionCanceledEvent.To.String()). + Str("Returned Subscription Amount Native", cancellationEvent.AmountNative.String()). + Str("Returned Subscription Amount Link", cancellationEvent.AmountLink.String()). + Str("SubID", cancellationEvent.SubId.String()). + Str("Returned to", cancellationEvent.To.String()). Msg("Subscription Canceled Event") - require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") - require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceNative, cancellationEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") + require.Equal(t, subBalanceLink, cancellationEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceNativeAfterSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeAfterSubCancelling, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), nil) require.NoError(t, err) - walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) //Verify that sub was deleted from Coordinator @@ -652,6 +654,7 @@ func TestVRFv2Plus(t *testing.T) { t.Run("Owner Withdraw", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -676,6 +679,7 @@ func TestVRFv2Plus(t *testing.T) { false, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err) @@ -687,44 +691,42 @@ func TestVRFv2Plus(t *testing.T) { true, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceNativeBeforeWithdraw, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeBeforeWithdraw, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), nil) require.NoError(t, err) - defaultWalletBalanceLinkBeforeWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) l.Info(). - Str("Returning to", defaultWalletAddress). + Str("Returning to", sethClient.MustGetRootKeyAddress().Hex()). Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") err = vrfContracts.CoordinatorV2Plus.Withdraw( - common.HexToAddress(defaultWalletAddress), + common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), ) require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") amountToWithdrawNative := fulfilledEventNative.Payment l.Info(). - Str("Returning to", defaultWalletAddress). + Str("Returning to", sethClient.MustGetRootKeyAddress().Hex()). Str("Amount", amountToWithdrawNative.String()). Msg("Invoking Oracle Withdraw for Native") err = vrfContracts.CoordinatorV2Plus.WithdrawNative( - common.HexToAddress(defaultWalletAddress), + common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), ) require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - - defaultWalletBalanceNativeAfterWithdraw, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeAfterWithdraw, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(sethClient.MustGetRootKeyAddress().Hex()), nil) require.NoError(t, err) - defaultWalletBalanceLinkAfterWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), sethClient.MustGetRootKeyAddress().Hex()) require.NoError(t, err) //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance @@ -739,7 +741,6 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -751,17 +752,16 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -780,15 +780,12 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = true consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -820,10 +817,12 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") @@ -846,7 +845,6 @@ func TestVRFv2PlusMigration(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -858,16 +856,16 @@ func TestVRFv2PlusMigration(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -886,9 +884,8 @@ func TestVRFv2PlusMigration(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") // Migrate subscription from old coordinator to new coordinator, verify if balances // are moved correctly and requests can be made successfully in the subscription in @@ -897,6 +894,7 @@ func TestVRFv2PlusMigration(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -922,12 +920,9 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, "error getting subscription information") //Migration Process - newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfContracts.BHS.Address()) + newCoordinator, err := contracts.DeployVRFCoordinatorV2PlusUpgradedVersion(sethClient, vrfContracts.BHS.Address()) require.NoError(t, err, "error deploying VRF CoordinatorV2PlusUpgradedVersion") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator, uint64(assets.GWei(*configCopy.VRFv2Plus.General.CLNodeMaxGasPriceGWei).Int64())) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfcommon.ErrRegisteringProvingKey, err)) @@ -946,8 +941,6 @@ func TestVRFv2PlusMigration(t *testing.T) { err = newCoordinator.SetLINKAndLINKNativeFeed(vrfContracts.LinkToken.Address(), vrfContracts.MockETHLINKFeed.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ ForwardingAllowed: *configCopy.VRFv2Plus.General.VRFJobForwardingAllowed, @@ -972,25 +965,14 @@ func TestVRFv2PlusMigration(t *testing.T) { err = vrfContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) require.NoError(t, err, "error registering migratable coordinator") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceBeforeMigration, migratedCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - - err = vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) - + _, migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) - migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) - require.NoError(t, err, "error waiting for MigrationCompleted event") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts.CoordinatorV2Plus) @@ -1055,6 +1037,7 @@ func TestVRFv2PlusMigration(t *testing.T) { false, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -1067,6 +1050,7 @@ func TestVRFv2PlusMigration(t *testing.T) { true, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") }) @@ -1079,6 +1063,7 @@ func TestVRFv2PlusMigration(t *testing.T) { wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( testcontext.Get(t), + l, env, chainID, &configCopy, @@ -1106,12 +1091,9 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, "error getting subscription information") //Migration Process - newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfContracts.BHS.Address()) + newCoordinator, err := contracts.DeployVRFCoordinatorV2PlusUpgradedVersion(sethClient, vrfContracts.BHS.Address()) require.NoError(t, err, "error deploying VRF CoordinatorV2PlusUpgradedVersion") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator, uint64(assets.GWei(*configCopy.VRFv2Plus.General.CLNodeMaxGasPriceGWei).Int64())) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfcommon.ErrRegisteringProvingKey, err)) @@ -1130,8 +1112,6 @@ func TestVRFv2PlusMigration(t *testing.T) { err = newCoordinator.SetLINKAndLINKNativeFeed(vrfContracts.LinkToken.Address(), vrfContracts.MockETHLINKFeed.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ ForwardingAllowed: *configCopy.VRFv2Plus.General.VRFJobForwardingAllowed, @@ -1156,26 +1136,15 @@ func TestVRFv2PlusMigration(t *testing.T) { err = vrfContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) require.NoError(t, err, "error registering migratable coordinator") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceBeforeMigration, migratedCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - // Migrate wrapper's sub using coordinator's migrate method - err = vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) - + _, migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) - migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) - require.NoError(t, err, "error waiting for MigrationCompleted event") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts.CoordinatorV2Plus) @@ -1269,7 +1238,6 @@ func TestVRFV2PlusWithBHS(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -1281,16 +1249,16 @@ func TestVRFV2PlusWithBHS(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -1314,9 +1282,8 @@ func TestVRFV2PlusWithBHS(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") var isNativeBilling = true t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { @@ -1327,6 +1294,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -1351,6 +1319,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness") @@ -1358,12 +1327,17 @@ func TestVRFV2PlusWithBHS(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //Wait at least 256 blocks - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), evmClient, &wg, time.Second*260, t) + _, err = actions.WaitForBlockNumberToBe( + randRequestBlockNumber+uint64(257), + sethClient, + &wg, + time.Second*260, + t, + l, + ) wg.Wait() require.NoError(t, err) err = vrfv2plus.FundSubscriptions( - env, - chainID, big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, @@ -1379,7 +1353,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling, 0) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) @@ -1402,6 +1376,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -1427,6 +1402,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness") randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber @@ -1435,12 +1411,17 @@ func TestVRFV2PlusWithBHS(t *testing.T) { var wg sync.WaitGroup wg.Add(1) - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*configCopy.VRFv2Plus.General.BHSJobWaitBlocks+10), evmClient, &wg, time.Minute*1, t) + _, err = actions.WaitForBlockNumberToBe( + randRequestBlockNumber+uint64(*configCopy.VRFv2Plus.General.BHSJobWaitBlocks+10), + sethClient, + &wg, + time.Minute*1, + t, + l, + ) wg.Wait() require.NoError(t, err, "error waiting for blocknumber to be") - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) metrics, err := consumers[0].GetLoadTestMetrics(testcontext.Get(t)) require.Equal(t, 0, metrics.RequestCount.Cmp(big.NewInt(1))) require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0))) @@ -1458,7 +1439,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { require.Equal(t, strings.ToLower(vrfContracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) - bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, common.HexToHash(txHash)) + bhsStoreTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), common.HexToHash(txHash)) require.NoError(t, err, "error getting tx from hash") bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) @@ -1467,9 +1448,6 @@ func TestVRFV2PlusWithBHS(t *testing.T) { Msg("BHS Node's Store Blockhash for Blocknumber Method TX") require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) - err = evmClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - var randRequestBlockHash [32]byte gom.Eventually(func(g gomega.Gomega) { randRequestBlockHash, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) @@ -1489,7 +1467,6 @@ func TestVRFV2PlusWithBHF(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -1498,20 +1475,19 @@ func TestVRFV2PlusWithBHF(t *testing.T) { config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus - chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -1543,9 +1519,9 @@ func TestVRFV2PlusWithBHF(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse( testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err) - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") var isNativeBilling = true t.Run("BHF Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { @@ -1556,6 +1532,7 @@ func TestVRFV2PlusWithBHF(t *testing.T) { configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -1580,6 +1557,7 @@ func TestVRFV2PlusWithBHF(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness") @@ -1587,15 +1565,20 @@ func TestVRFV2PlusWithBHF(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //Wait at least 260 blocks - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(260), evmClient, &wg, time.Second*262, t) + _, err = actions.WaitForBlockNumberToBe( + randRequestBlockNumber+uint64(260), + sethClient, + &wg, + time.Second*262, + t, + l, + ) wg.Wait() require.NoError(t, err) l.Info().Float64("SubscriptionFundingAmountNative", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative). Float64("SubscriptionFundingAmountLink", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink). Msg("Funding subscription") err = vrfv2plus.FundSubscriptions( - env, - chainID, big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, @@ -1611,7 +1594,7 @@ func TestVRFV2PlusWithBHF(t *testing.T) { }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling, 0) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) @@ -1644,7 +1627,6 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode ) @@ -1656,16 +1638,16 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -1690,15 +1672,12 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - t.Run("Timed out request fulfilled after node restart with replay", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -1724,6 +1703,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for requested event") @@ -1735,6 +1715,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { Int("Number of Subs to create", 1). Msg("Creating and funding subscriptions, adding consumers") fundedSubIDs, err := vrfv2plus.CreateFundSubsAndAddConsumers( + testcontext.Get(t), env, chainID, fundingLinkAmt, @@ -1753,6 +1734,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") require.True(t, randomWordsFulfilledEvent.Success, "RandomWordsFulfilled Event's `Success` field should be true") @@ -1762,8 +1744,6 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { // 5. fund sub so that node can fulfill request err = vrfv2plus.FundSubscriptions( - env, - chainID, fundingLinkAmt, fundingNativeAmt, vrfContracts.LinkToken, @@ -1844,7 +1824,6 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) env *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts subIDsForCancellingAfterTest []*big.Int - defaultWalletAddress string vrfKey *vrfcommon.VRFKeyData ) l := logging.GetTestLogger(t) @@ -1855,16 +1834,16 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l) } } if !*vrfv2PlusConfig.General.UseExistingEnv { @@ -1887,11 +1866,8 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -1921,6 +1897,7 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) isNativeBilling, config.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -1947,12 +1924,11 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { @@ -1989,13 +1965,13 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, chainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() - var isNativeBilling = true + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -2025,6 +2001,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err) @@ -2035,7 +2012,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { require.NoError(t, err, "error getting rpc url") //2. rewind chain by n number of blocks - basically, mimicking reorg scenario - latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), evmClient, rpcUrl, rewindChainToBlock, l) + latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), sethClient, rpcUrl, rewindChainToBlock, l) require.NoError(t, err, fmt.Sprintf("error rewinding chain to block number %d", rewindChainToBlock)) //3.1 ensure that chain is reorged and latest block number is greater than the block number when request was made @@ -2052,6 +2029,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, + 0, ) require.NoError(t, err, "error waiting for randomness fulfilled event") }) @@ -2070,6 +2048,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err) @@ -2080,7 +2059,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { require.NoError(t, err, "error getting rpc url") //3. rewind chain by n number of blocks - basically, mimicking reorg scenario - latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), evmClient, rpcUrl, rewindChainToBlockNumber, l) + latestBlockNumberAfterReorg, err := actions.RewindSimulatedChainToBlockNumber(testcontext.Get(t), sethClient, rpcUrl, rewindChainToBlockNumber, l) require.NoError(t, err, fmt.Sprintf("error rewinding chain to block number %d", rewindChainToBlockNumber)) //4. ensure that chain is reorged and latest block number is less than the block number when request was made @@ -2120,12 +2099,11 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID cleanupFn := func() { - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - if evmClient.NetworkSimulated() { + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + if sethClient.Cfg.IsSimulatedNetwork() { l.Info(). - Str("Network Name", evmClient.GetNetworkName()). + Str("Network Name", sethClient.Cfg.Network.Name). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { @@ -2149,9 +2127,8 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l, test_env.DefaultChainlinkNodeLogScannerSettings) require.NoError(t, err, "Error setting up VRFv2Plus universe") - evmClient, err := env.GetEVMClient(chainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - defaultWalletAddress = evmClient.GetDefaultWallet().Address() + sethClient, err := env.GetSethClient(chainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") //batchMaxGas := config.MaxGasLimit() (2.5 mill) + 400_000 = 2.9 mill //callback gas limit set by consumer = 500k @@ -2203,6 +2180,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { vrfNode.Job = job consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -2230,6 +2208,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -2256,7 +2235,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { // verify that all fulfillments should be inside one tx require.Equal(t, 1, len(batchFulfillmentTxs)) - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTXToAddress := fulfillmentTx.To().String() @@ -2268,7 +2247,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { // verify that VRF node sends fulfillments via BatchCoordinator contract require.Equal(t, vrfContracts.BatchCoordinatorV2Plus.Address(), fulfillmentTXToAddress, "Fulfillment Tx To Address should be the BatchCoordinatorV2Plus Address when batch fulfillment is enabled") - fulfillmentTxReceipt, err := evmClient.GetTxReceipt(fulfillmentTx.Hash()) + fulfillmentTxReceipt, err := sethClient.Client.TransactionReceipt(testcontext.Get(t), fulfillmentTx.Hash()) require.NoError(t, err) randomWordsFulfilledLogs, err := contracts.ParseRandomWordsFulfilledLogs(vrfContracts.CoordinatorV2Plus, fulfillmentTxReceipt.Logs) @@ -2317,6 +2296,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { vrfNode.Job = job consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testcontext.Get(t), env, chainID, vrfContracts.CoordinatorV2Plus, @@ -2344,6 +2324,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { isNativeBilling, configCopy.VRFv2Plus.General, l, + 0, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -2358,7 +2339,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Request/Fulfilment Stats") - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := sethClient.Client.TransactionByHash(testcontext.Get(t), randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTXToAddress := fulfillmentTx.To().String() diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index 6de19ee57d1..6ca5d4aec28 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -209,4 +209,59 @@ gas_price = 50_000_000 # EIP-1559 transactions gas_fee_cap = 3_800_000_000 -gas_tip_cap = 1_800_000_000 \ No newline at end of file +gas_tip_cap = 1_800_000_000 + + +[[Seth.networks]] +name = "ARBITRUM_SEPOLIA" +chain_id = "421614" +transaction_timeout = "1m" + +# if set to true we will estimate gas for every transaction +gas_price_estimation_enabled = true + +# transfer_gas_fee is gas limit that will be used, when funding CL nodes and returning funds from there and when funding and returning funds from ephemeral keys +# we use hardcoded value in order to be estimate how much funds are available for sending or returning after tx costs have been paid +transfer_gas_fee = 50_000 +# gas limit should be explicitly set only if you are connecting to a node that's incapable of estimating gas limit itself (should only happen for very old versions) +# gas_limit = 100_000_000 + +# manual settings, used when gas_price_estimation_enabled is false or when it fails +# legacy transactions +gas_price = 50_000_000_000 +# EIP-1559 transactions +eip_1559_dynamic_fees = true +gas_fee_cap = 50_000_000_000 +gas_tip_cap = 2_000_000_000 + +# how many last blocks to use, when estimating gas for a transaction +gas_price_estimation_blocks = 100 +# priority of the transaction, can be "fast", "standard" or "slow" (the higher the priority, the higher adjustment factor will be used for gas estimation) [default: "standard"] +gas_price_estimation_tx_priority = "standard" + +[[Seth.networks]] +name = "POLYGON_AMOY" +chain_id = "80002" +transaction_timeout = "1m" + +# if set to true we will estimate gas for every transaction +gas_price_estimation_enabled = true + +# transfer_gas_fee is gas limit that will be used, when funding CL nodes and returning funds from there and when funding and returning funds from ephemeral keys +# we use hardcoded value in order to be estimate how much funds are available for sending or returning after tx costs have been paid +transfer_gas_fee = 21_000 +# gas limit should be explicitly set only if you are connecting to a node that's incapable of estimating gas limit itself (should only happen for very old versions) +# gas_limit = 100_000_000 + +# manual settings, used when gas_price_estimation_enabled is false or when it fails +# legacy transactions +gas_price = 200_000_000_000 +# EIP-1559 transactions +eip_1559_dynamic_fees = true +gas_fee_cap = 200_000_000_000 +gas_tip_cap = 2_000_000_000 + +# how many last blocks to use, when estimating gas for a transaction +gas_price_estimation_blocks = 100 +# priority of the transaction, can be "fast", "standard" or "slow" (the higher the priority, the higher adjustment factor will be used for gas estimation) [default: "standard"] +gas_price_estimation_tx_priority = "standard" diff --git a/integration-tests/utils/seth.go b/integration-tests/utils/seth.go index cc5f1c60485..af953f49d48 100644 --- a/integration-tests/utils/seth.go +++ b/integration-tests/utils/seth.go @@ -132,3 +132,15 @@ func ValidateSethNetworkConfig(cfg *seth.Network) error { return nil } + +const RootKeyNum = 0 + +// AvailableSethKeyNum returns the available Seth address index +// If there are multiple addresses, it will return any synced key +// Otherwise it will return the root key +func AvailableSethKeyNum(client *seth.Client) int { + if len(client.Addresses) > 1 { + return client.AnySyncedKey() + } + return RootKeyNum +} From ecfab64b5b9847b4dc92bfc8373b3ffc7ef9abdb Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 16 May 2024 04:14:56 -0500 Subject: [PATCH 16/17] Implement DSL for LogPoller (#12793) * Implement DSL for LogPoller This commit implements the query DSL within LogPoller by remapping comparer filters to topic and word filters. A parser then creates an SQL statement from the remapped events and queries the log poller database directly. * added binding check on QueryKey * update int parsing bit size * added extensive log poller orm tests for query capability * update topic filter test * address comments * add query name to logpoller ORM FilterLogs for query observability * update tests from common and return empty list on empty query --- core/chains/evm/logpoller/disabled.go | 4 +- core/chains/evm/logpoller/log_poller.go | 7 +- core/chains/evm/logpoller/mocks/log_poller.go | 18 +- core/chains/evm/logpoller/observability.go | 7 + core/chains/evm/logpoller/orm.go | 42 +- core/chains/evm/logpoller/orm_test.go | 414 ++++++++++++++- core/chains/evm/logpoller/parser.go | 502 ++++++++++++++++++ core/chains/evm/logpoller/parser_test.go | 339 ++++++++++++ core/chains/evm/logpoller/query.go | 114 ++-- core/chains/evm/logpoller/query_test.go | 4 +- core/services/relay/evm/chain_reader.go | 60 +-- core/services/relay/evm/chain_reader_test.go | 9 + core/services/relay/evm/dsl.go | 96 ---- core/services/relay/evm/event_binding.go | 144 +++-- core/services/relay/evm/pgparser.go | 36 -- 15 files changed, 1482 insertions(+), 314 deletions(-) create mode 100644 core/chains/evm/logpoller/parser.go create mode 100644 core/chains/evm/logpoller/parser_test.go delete mode 100644 core/services/relay/evm/dsl.go delete mode 100644 core/services/relay/evm/pgparser.go diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index 3a1e4ba4fe6..f30837bcfee 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -118,8 +118,8 @@ func (d disabled) LogsDataWordBetween(ctx context.Context, eventSig common.Hash, return nil, ErrDisabled } -func (d disabled) FilteredLogs(_ query.KeyFilter, _ query.LimitAndSort) ([]Log, error) { - return nil, nil +func (d disabled) FilteredLogs(_ context.Context, _ query.KeyFilter, _ query.LimitAndSort, _ string) ([]Log, error) { + return nil, ErrDisabled } func (d disabled) FindLCA(ctx context.Context) (*LogPollerBlock, error) { diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index b1d7d1da623..e964b86221c 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -67,7 +67,8 @@ type LogPoller interface { LogsDataWordGreaterThan(ctx context.Context, eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs evmtypes.Confirmations) ([]Log, error) LogsDataWordBetween(ctx context.Context, eventSig common.Hash, address common.Address, wordIndexMin, wordIndexMax int, wordValue common.Hash, confs evmtypes.Confirmations) ([]Log, error) - FilteredLogs(filter query.KeyFilter, limitAndSrt query.LimitAndSort) ([]Log, error) + // chainlink-common query filtering + FilteredLogs(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, queryName string) ([]Log, error) } type LogPollerTest interface { @@ -1522,6 +1523,6 @@ func EvmWord(i uint64) common.Hash { return common.BytesToHash(b) } -func (lp *logPoller) FilteredLogs(queryFilter query.KeyFilter, sortAndLimit query.LimitAndSort) ([]Log, error) { - return lp.orm.FilteredLogs(queryFilter, sortAndLimit) +func (lp *logPoller) FilteredLogs(ctx context.Context, queryFilter query.KeyFilter, limitAndSort query.LimitAndSort, queryName string) ([]Log, error) { + return lp.orm.FilteredLogs(ctx, queryFilter, limitAndSort, queryName) } diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index e30aac56c8b..3c8f445df57 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -59,9 +59,9 @@ func (_m *LogPoller) DeleteLogsAndBlocksAfter(ctx context.Context, start int64) return r0 } -// FilteredLogs provides a mock function with given fields: filter, limitAndSrt -func (_m *LogPoller) FilteredLogs(filter query.KeyFilter, limitAndSrt query.LimitAndSort) ([]logpoller.Log, error) { - ret := _m.Called(filter, limitAndSrt) +// FilteredLogs provides a mock function with given fields: ctx, filter, limitAndSort, queryName +func (_m *LogPoller) FilteredLogs(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, queryName string) ([]logpoller.Log, error) { + ret := _m.Called(ctx, filter, limitAndSort, queryName) if len(ret) == 0 { panic("no return value specified for FilteredLogs") @@ -69,19 +69,19 @@ func (_m *LogPoller) FilteredLogs(filter query.KeyFilter, limitAndSrt query.Limi var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(query.KeyFilter, query.LimitAndSort) ([]logpoller.Log, error)); ok { - return rf(filter, limitAndSrt) + if rf, ok := ret.Get(0).(func(context.Context, query.KeyFilter, query.LimitAndSort, string) ([]logpoller.Log, error)); ok { + return rf(ctx, filter, limitAndSort, queryName) } - if rf, ok := ret.Get(0).(func(query.KeyFilter, query.LimitAndSort) []logpoller.Log); ok { - r0 = rf(filter, limitAndSrt) + if rf, ok := ret.Get(0).(func(context.Context, query.KeyFilter, query.LimitAndSort, string) []logpoller.Log); ok { + r0 = rf(ctx, filter, limitAndSort, queryName) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]logpoller.Log) } } - if rf, ok := ret.Get(1).(func(query.KeyFilter, query.LimitAndSort) error); ok { - r1 = rf(filter, limitAndSrt) + if rf, ok := ret.Get(1).(func(context.Context, query.KeyFilter, query.LimitAndSort, string) error); ok { + r1 = rf(ctx, filter, limitAndSort, queryName) } else { r1 = ret.Error(1) } diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index 361b8610905..7842a060eca 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/types/query" ) type queryType string @@ -261,6 +262,12 @@ func (o *ObservedORM) SelectIndexedLogsTopicRange(ctx context.Context, address c }) } +func (o *ObservedORM) FilteredLogs(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, queryName string) ([]Log, error) { + return withObservedQueryAndResults(o, queryName, func() ([]Log, error) { + return o.ORM.FilteredLogs(ctx, filter, limitAndSort, queryName) + }) +} + func withObservedQueryAndResults[T any](o *ObservedORM, queryName string, query func() ([]T, error)) ([]T, error) { results, err := withObservedQuery(o, queryName, query) if err == nil { diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index 3cd8db74849..8a4c46bd7a6 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -61,8 +61,9 @@ type ORM interface { SelectLogsDataWordRange(ctx context.Context, address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs evmtypes.Confirmations) ([]Log, error) SelectLogsDataWordGreaterThan(ctx context.Context, address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs evmtypes.Confirmations) ([]Log, error) SelectLogsDataWordBetween(ctx context.Context, address common.Address, eventSig common.Hash, wordIndexMin int, wordIndexMax int, wordValue common.Hash, confs evmtypes.Confirmations) ([]Log, error) + // FilteredLogs accepts chainlink-common filtering DSL. - FilteredLogs(filter query.KeyFilter, sortAndLimit query.LimitAndSort) ([]Log, error) + FilteredLogs(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, queryName string) ([]Log, error) } type DSORM struct { @@ -92,10 +93,10 @@ func (o *DSORM) new(ds sqlutil.DataSource) *DSORM { return NewORM(o.chainID, ds, // InsertBlock is idempotent to support replays. func (o *DSORM) InsertBlock(ctx context.Context, blockHash common.Hash, blockNumber int64, blockTimestamp time.Time, finalizedBlock int64) error { args, err := newQueryArgs(o.chainID). - withCustomHashArg("block_hash", blockHash). - withCustomArg("block_number", blockNumber). - withCustomArg("block_timestamp", blockTimestamp). - withCustomArg("finalized_block_number", finalizedBlock). + withField("block_hash", blockHash). + withField("block_number", blockNumber). + withField("block_timestamp", blockTimestamp). + withField("finalized_block_number", finalizedBlock). toArgs() if err != nil { return err @@ -115,7 +116,7 @@ func (o *DSORM) InsertBlock(ctx context.Context, blockHash common.Hash, blockNum func (o *DSORM) InsertFilter(ctx context.Context, filter Filter) (err error) { topicArrays := []types.HashArray{filter.Topic2, filter.Topic3, filter.Topic4} args, err := newQueryArgs(o.chainID). - withCustomArg("name", filter.Name). + withField("name", filter.Name). withRetention(filter.Retention). withMaxLogsKept(filter.MaxLogsKept). withLogsPerBlock(filter.LogsPerBlock). @@ -930,8 +931,8 @@ func (o *DSORM) SelectIndexedLogsWithSigsExcluding(ctx context.Context, sigA, si withTopicIndex(topicIndex). withStartBlock(startBlock). withEndBlock(endBlock). - withCustomHashArg("sigA", sigA). - withCustomHashArg("sigB", sigB). + withField("sigA", sigA). + withField("sigB", sigB). withConfs(confs). toArgs() if err != nil { @@ -970,9 +971,28 @@ func (o *DSORM) SelectIndexedLogsWithSigsExcluding(ctx context.Context, sigA, si return logs, nil } -func (o *DSORM) FilteredLogs(_ query.KeyFilter, _ query.LimitAndSort) ([]Log, error) { - //TODO implement me - panic("implement me") +func (o *DSORM) FilteredLogs(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, _ string) ([]Log, error) { + qs, args, err := (&pgDSLParser{}).buildQuery(o.chainID, filter.Expressions, limitAndSort) + if err != nil { + return nil, err + } + + values, err := args.toArgs() + if err != nil { + return nil, err + } + + query, sqlArgs, err := o.ds.BindNamed(qs, values) + if err != nil { + return nil, err + } + + var logs []Log + if err = o.ds.SelectContext(ctx, &logs, query, sqlArgs...); err != nil { + return nil, err + } + + return logs, nil } func nestedBlockNumberQuery(confs evmtypes.Confirmations) string { diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 7e6ce9aada2..b2f01360844 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -19,6 +19,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/types/query" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -595,47 +597,156 @@ func TestORM_IndexedLogs(t *testing.T) { insertLogsTopicValueRange(t, th.ChainID, o1, addr, 1, eventSig, 1, 3) insertLogsTopicValueRange(t, th.ChainID, o1, addr, 2, eventSig, 4, 4) // unconfirmed + filtersForTopics := func(topicIdx uint64, topicValues []uint64) query.Expression { + topicFilters := query.BoolExpression{ + Expressions: make([]query.Expression, len(topicValues)), + BoolOperator: query.OR, + } + + for idx, value := range topicValues { + topicFilters.Expressions[idx] = logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(value).Hex(), Operator: primitives.Eq}, + }) + } + + return query.Expression{BoolExpression: topicFilters} + } + + limiter := query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)) + standardFilter := func(topicIdx uint64, topicValues []uint64) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + filtersForTopics(topicIdx, topicValues), + query.Confirmation(primitives.Unconfirmed), + }, + } + } + lgs, err := o1.SelectIndexedLogs(ctx, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}, 0) require.NoError(t, err) require.Equal(t, 1, len(lgs)) assert.Equal(t, logpoller.EvmWord(1).Bytes(), lgs[0].GetTopics()[1].Bytes()) + lgs, err = o1.FilteredLogs(ctx, standardFilter(1, []uint64{1}), limiter, "") + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + assert.Equal(t, logpoller.EvmWord(1).Bytes(), lgs[0].GetTopics()[1].Bytes()) + lgs, err = o1.SelectIndexedLogs(ctx, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1), logpoller.EvmWord(2)}, 0) require.NoError(t, err) assert.Equal(t, 2, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, standardFilter(1, []uint64{1, 2}), limiter, "") + require.NoError(t, err) + assert.Equal(t, 2, len(lgs)) + + blockRangeFilter := func(start, end uint64, topicIdx uint64, topicValues []uint64) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + filtersForTopics(topicIdx, topicValues), + query.Block(start, primitives.Gte), + query.Block(end, primitives.Lte), + }, + } + } + lgs, err = o1.SelectIndexedLogsByBlockRange(ctx, 1, 1, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 1, 1, []uint64{1}), limiter, "") + require.NoError(t, err) + assert.Equal(t, 1, len(lgs)) + lgs, err = o1.SelectIndexedLogsByBlockRange(ctx, 1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(2)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 1, []uint64{2}), limiter, "") + require.NoError(t, err) + assert.Equal(t, 1, len(lgs)) + lgs, err = o1.SelectIndexedLogsByBlockRange(ctx, 1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 1, []uint64{1}), limiter, "") + require.NoError(t, err) + assert.Equal(t, 1, len(lgs)) + _, err = o1.SelectIndexedLogsByBlockRange(ctx, 1, 2, addr, eventSig, 0, []common.Hash{logpoller.EvmWord(1)}) require.Error(t, err) assert.Contains(t, err.Error(), "invalid index for topic: 0") + + _, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 0, []uint64{1}), limiter, "") + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid index for topic: 0") + _, err = o1.SelectIndexedLogsByBlockRange(ctx, 1, 2, addr, eventSig, 4, []common.Hash{logpoller.EvmWord(1)}) require.Error(t, err) assert.Contains(t, err.Error(), "invalid index for topic: 4") + _, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 4, []uint64{1}), limiter, "") + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid index for topic: 4") + lgs, err = o1.SelectIndexedLogsTopicGreaterThan(ctx, addr, eventSig, 1, logpoller.EvmWord(2), 0) require.NoError(t, err) assert.Equal(t, 2, len(lgs)) + filter := query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + logpoller.NewEventByTopicFilter(1, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(2).Hex(), Operator: primitives.Gte}, + }), + query.Confirmation(primitives.Unconfirmed), + }, + } + + lgs, err = o1.FilteredLogs(ctx, filter, limiter, "") + require.NoError(t, err) + assert.Equal(t, 2, len(lgs)) + + rangeFilter := func(topicIdx uint64, min, max uint64) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(min).Hex(), Operator: primitives.Gte}, + }), + logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(max).Hex(), Operator: primitives.Lte}, + }), + query.Confirmation(primitives.Unconfirmed), + }, + } + } + lgs, err = o1.SelectIndexedLogsTopicRange(ctx, addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) assert.Equal(t, logpoller.EvmWord(3).Bytes(), lgs[0].GetTopics()[1].Bytes()) + lgs, err = o1.FilteredLogs(ctx, rangeFilter(1, 3, 3), limiter, "") + require.NoError(t, err) + assert.Equal(t, 1, len(lgs)) + assert.Equal(t, logpoller.EvmWord(3).Bytes(), lgs[0].GetTopics()[1].Bytes()) + lgs, err = o1.SelectIndexedLogsTopicRange(ctx, addr, eventSig, 1, logpoller.EvmWord(1), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 3, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, rangeFilter(1, 1, 3), limiter, "") + require.NoError(t, err) + assert.Equal(t, 3, len(lgs)) + // Check confirmations work as expected. require.NoError(t, o1.InsertBlock(ctx, common.HexToHash("0x2"), 2, time.Now(), 0)) lgs, err = o1.SelectIndexedLogsTopicRange(ctx, addr, eventSig, 1, logpoller.EvmWord(4), logpoller.EvmWord(4), 1) @@ -712,6 +823,22 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { require.Equal(t, 2, len(retrievedLogs)) require.Equal(t, retrievedLogs[0].LogIndex, logs[0].LogIndex) require.Equal(t, retrievedLogs[1].LogIndex, logs[1].LogIndex) + + limiter := query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)) + filter := query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + query.TxHash(txHash.Hex()), + }, + } + + retrievedLogs, err = o1.FilteredLogs(ctx, filter, limiter, "") + require.NoError(t, err) + + require.Equal(t, 2, len(retrievedLogs)) + require.Equal(t, retrievedLogs[0].LogIndex, logs[0].LogIndex) + require.Equal(t, retrievedLogs[1].LogIndex, logs[1].LogIndex) } func TestORM_DataWords(t *testing.T) { @@ -746,25 +873,61 @@ func TestORM_DataWords(t *testing.T) { Data: append(logpoller.EvmWord(2).Bytes(), logpoller.EvmWord(3).Bytes()...), }, })) + + wordFilter := func(wordIdx uint8, word1, word2 uint64) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + logpoller.NewEventByWordFilter(eventSig, wordIdx, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(word1).Hex(), Operator: primitives.Gte}, + }), + logpoller.NewEventByWordFilter(eventSig, wordIdx, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(word2).Hex(), Operator: primitives.Lte}, + }), + query.Confirmation(primitives.Unconfirmed), + }, + } + } + + limiter := query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)) + // Outside range should fail. lgs, err := o1.SelectLogsDataWordRange(ctx, addr, eventSig, 0, logpoller.EvmWord(2), logpoller.EvmWord(2), 0) require.NoError(t, err) require.Equal(t, 0, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, wordFilter(0, 2, 2), limiter, "") + require.NoError(t, err) + require.Equal(t, 0, len(lgs)) + // Range including log should succeed lgs, err = o1.SelectLogsDataWordRange(ctx, addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(2), 0) require.NoError(t, err) require.Equal(t, 1, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, wordFilter(0, 1, 2), limiter, "") + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + // Range only covering log should succeed lgs, err = o1.SelectLogsDataWordRange(ctx, addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(1), 0) require.NoError(t, err) require.Equal(t, 1, len(lgs)) + lgs, err = o1.FilteredLogs(ctx, wordFilter(0, 1, 1), limiter, "") + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + // Cannot query for unconfirmed second log. lgs, err = o1.SelectLogsDataWordRange(ctx, addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) require.NoError(t, err) require.Equal(t, 0, len(lgs)) + + lgs, err = o1.FilteredLogs(ctx, wordFilter(1, 3, 3), limiter, "") + require.NoError(t, err) + require.Equal(t, 0, len(lgs)) + // Confirm it, then can query. require.NoError(t, o1.InsertBlock(ctx, common.HexToHash("0x2"), 2, time.Now(), 0)) lgs, err = o1.SelectLogsDataWordRange(ctx, addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) @@ -772,10 +935,30 @@ func TestORM_DataWords(t *testing.T) { require.Equal(t, 1, len(lgs)) require.Equal(t, lgs[0].Data, append(logpoller.EvmWord(2).Bytes(), logpoller.EvmWord(3).Bytes()...)) + lgs, err = o1.FilteredLogs(ctx, wordFilter(1, 3, 3), limiter, "") + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + require.Equal(t, lgs[0].Data, append(logpoller.EvmWord(2).Bytes(), logpoller.EvmWord(3).Bytes()...)) + // Check greater than 1 yields both logs. lgs, err = o1.SelectLogsDataWordGreaterThan(ctx, addr, eventSig, 0, logpoller.EvmWord(1), 0) require.NoError(t, err) assert.Equal(t, 2, len(lgs)) + + filter := query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(addr), + logpoller.NewEventSigFilter(eventSig), + logpoller.NewEventByWordFilter(eventSig, 0, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(1).Hex(), Operator: primitives.Gte}, + }), + query.Confirmation(primitives.Unconfirmed), + }, + } + + lgs, err = o1.FilteredLogs(ctx, filter, limiter, "") + require.NoError(t, err) + assert.Equal(t, 2, len(lgs)) } func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { @@ -859,18 +1042,65 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { } require.NoError(t, o1.InsertLogs(ctx, inputLogs)) + filter := func(sigs []common.Hash, startBlock, endBlock int64) query.KeyFilter { + filters := []query.Expression{ + logpoller.NewAddressFilter(sourceAddr), + } + + if len(sigs) > 0 { + exp := make([]query.Expression, len(sigs)) + for idx, val := range sigs { + exp[idx] = logpoller.NewEventSigFilter(val) + } + + filters = append(filters, query.Expression{ + BoolExpression: query.BoolExpression{ + Expressions: exp, + BoolOperator: query.OR, + }, + }) + } + + filters = append(filters, query.Expression{ + BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.Block(uint64(startBlock), primitives.Gte), + query.Block(uint64(endBlock), primitives.Lte), + }, + BoolOperator: query.AND, + }, + }) + + return query.KeyFilter{ + Expressions: filters, + } + } + + limiter := query.LimitAndSort{ + SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)}, + } + + assertion := func(t *testing.T, logs []logpoller.Log, err error, startBlock, endBlock int64) { + require.NoError(t, err) + assert.Len(t, logs, 4) + for _, l := range logs { + assert.Equal(t, sourceAddr, l.Address, "wrong log address") + assert.True(t, bytes.Equal(topic.Bytes(), l.EventSig.Bytes()) || bytes.Equal(topic2.Bytes(), l.EventSig.Bytes()), "wrong log topic") + assert.True(t, l.BlockNumber >= startBlock && l.BlockNumber <= endBlock) + } + } + startBlock, endBlock := int64(10), int64(15) logs, err := o1.SelectLogsWithSigs(ctx, startBlock, endBlock, sourceAddr, []common.Hash{ topic, topic2, }) - require.NoError(t, err) - assert.Len(t, logs, 4) - for _, l := range logs { - assert.Equal(t, sourceAddr, l.Address, "wrong log address") - assert.True(t, bytes.Equal(topic.Bytes(), l.EventSig.Bytes()) || bytes.Equal(topic2.Bytes(), l.EventSig.Bytes()), "wrong log topic") - assert.True(t, l.BlockNumber >= startBlock && l.BlockNumber <= endBlock) - } + + assertion(t, logs, err, startBlock, endBlock) + + logs, err = th.ORM.FilteredLogs(ctx, filter([]common.Hash{topic, topic2}, startBlock, endBlock), limiter, "") + + assertion(t, logs, err, startBlock, endBlock) } func TestORM_DeleteBlocksBefore(t *testing.T) { @@ -930,6 +1160,17 @@ func TestLogPoller_Logs(t *testing.T) { assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[4].BlockHash.String()) assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[5].BlockHash.String()) + logFilter := func(start, end uint64, address common.Address) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(address), + logpoller.NewEventSigFilter(event1), + query.Block(start, primitives.Gte), + query.Block(end, primitives.Lte), + }, + } + } + // Filter by Address and topic lgs, err = th.ORM.SelectLogs(ctx, 1, 3, address1, event1) require.NoError(t, err) @@ -940,6 +1181,17 @@ func TestLogPoller_Logs(t *testing.T) { assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[1].BlockHash.String()) assert.Equal(t, address1, lgs[1].Address) + lgs, err = th.ORM.FilteredLogs(ctx, logFilter(1, 3, address1), query.LimitAndSort{ + SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)}, + }, "") + require.NoError(t, err) + require.Equal(t, 2, len(lgs)) + assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000003", lgs[0].BlockHash.String()) + assert.Equal(t, address1, lgs[0].Address) + assert.Equal(t, event1.Bytes(), lgs[0].Topics[0]) + assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[1].BlockHash.String()) + assert.Equal(t, address1, lgs[1].Address) + // Filter by block lgs, err = th.ORM.SelectLogs(ctx, 2, 2, address2, event1) require.NoError(t, err) @@ -948,6 +1200,16 @@ func TestLogPoller_Logs(t *testing.T) { assert.Equal(t, int64(1), lgs[0].LogIndex) assert.Equal(t, address2, lgs[0].Address) assert.Equal(t, event1.Bytes(), lgs[0].Topics[0]) + + lgs, err = th.ORM.FilteredLogs(ctx, logFilter(2, 2, address2), query.LimitAndSort{ + SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)}, + }, "") + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000004", lgs[0].BlockHash.String()) + assert.Equal(t, int64(1), lgs[0].LogIndex) + assert.Equal(t, address2, lgs[0].Address) + assert.Equal(t, event1.Bytes(), lgs[0].Topics[0]) } func BenchmarkLogs(b *testing.B) { @@ -1404,29 +1666,92 @@ func TestSelectLogsCreatedAfter(t *testing.T) { }, }, } + + filter := func(timestamp time.Time, confs evmtypes.Confirmations, topicIdx int, topicVals []common.Hash) query.KeyFilter { + var queryConfs primitives.ConfirmationLevel + + switch confs { + case evmtypes.Finalized: + queryConfs = primitives.Finalized + case evmtypes.Unconfirmed: + queryConfs = primitives.Unconfirmed + default: + fmt.Println("default") + queryConfs = primitives.ConfirmationLevel(confs) + } + + filters := []query.Expression{ + logpoller.NewAddressFilter(address), + logpoller.NewEventSigFilter(event), + } + + if len(topicVals) > 0 { + exp := make([]query.Expression, len(topicVals)) + for idx, val := range topicVals { + exp[idx] = logpoller.NewEventByTopicFilter(uint64(topicIdx), []primitives.ValueComparator{ + {Value: val.String(), Operator: primitives.Eq}, + }) + } + + filters = append(filters, query.Expression{ + BoolExpression: query.BoolExpression{ + Expressions: exp, + BoolOperator: query.OR, + }, + }) + } + + filters = append(filters, []query.Expression{ + query.Timestamp(uint64(timestamp.Unix()), primitives.Gt), + query.Confirmation(queryConfs), + }...) + + return query.KeyFilter{ + Expressions: filters, + } + } + + limiter := query.LimitAndSort{ + SortBy: []query.SortBy{ + query.NewSortBySequence(query.Asc), + }, + } + + assertion := func(t *testing.T, logs []logpoller.Log, err error, exp []expectedLog) { + require.NoError(t, err) + require.Len(t, logs, len(exp)) + + for i, log := range logs { + assert.Equal(t, exp[i].block, log.BlockNumber) + assert.Equal(t, exp[i].log, log.LogIndex) + } + } + for _, tt := range tests { - t.Run("SelectLogsCreatedAfter"+tt.name, func(t *testing.T) { + t.Run(tt.name, func(t *testing.T) { logs, err := th.ORM.SelectLogsCreatedAfter(ctx, address, event, tt.after, tt.confs) - require.NoError(t, err) - require.Len(t, logs, len(tt.expectedLogs)) - for i, log := range logs { - require.Equal(t, tt.expectedLogs[i].block, log.BlockNumber) - require.Equal(t, tt.expectedLogs[i].log, log.LogIndex) - } - }) + assertion(t, logs, err, tt.expectedLogs) - t.Run("SelectIndexedLogsCreatedAfter"+tt.name, func(t *testing.T) { - logs, err := th.ORM.SelectIndexedLogsCreatedAfter(ctx, address, event, 1, []common.Hash{event}, tt.after, tt.confs) - require.NoError(t, err) - require.Len(t, logs, len(tt.expectedLogs)) + logs, err = th.ORM.FilteredLogs(ctx, filter(tt.after, tt.confs, 0, nil), limiter, "") - for i, log := range logs { - require.Equal(t, tt.expectedLogs[i].block, log.BlockNumber) - require.Equal(t, tt.expectedLogs[i].log, log.LogIndex) - } + assertion(t, logs, err, tt.expectedLogs) }) } + + t.Run("SelectIndexedLogsCreatedAfter", func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + logs, err := th.ORM.SelectIndexedLogsCreatedAfter(ctx, address, event, 1, []common.Hash{event}, tt.after, tt.confs) + + assertion(t, logs, err, tt.expectedLogs) + + logs, err = th.ORM.FilteredLogs(ctx, filter(tt.after, tt.confs, 1, []common.Hash{event}), limiter, "") + + assertion(t, logs, err, tt.expectedLogs) + }) + } + }) } func TestNestedLogPollerBlocksQuery(t *testing.T) { @@ -1612,6 +1937,12 @@ func TestSelectLogsDataWordBetween(t *testing.T) { logpoller.NewLogPollerBlock(utils.RandomBytes32(), 10, time.Now(), 1), ) require.NoError(t, err) + limiter := query.LimitAndSort{ + SortBy: []query.SortBy{ + query.NewSortByBlock(query.Asc), + query.NewSortBySequence(query.Asc), + }, + } tests := []struct { name string @@ -1640,15 +1971,40 @@ func TestSelectLogsDataWordBetween(t *testing.T) { }, } + wordFilter := func(word uint64) query.KeyFilter { + return query.KeyFilter{ + Expressions: []query.Expression{ + logpoller.NewAddressFilter(address), + logpoller.NewEventSigFilter(eventSig), + logpoller.NewEventByWordFilter(eventSig, 0, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(word).Hex(), Operator: primitives.Lte}, + }), + logpoller.NewEventByWordFilter(eventSig, 1, []primitives.ValueComparator{ + {Value: logpoller.EvmWord(word).Hex(), Operator: primitives.Gte}, + }), + query.Confirmation(primitives.Unconfirmed), + }, + } + } + + assertion := func(t *testing.T, logs []logpoller.Log, err error, expected []int64) { + require.NoError(t, err) + assert.Len(t, logs, len(expected)) + + for index := range logs { + assert.Equal(t, expected[index], logs[index].BlockNumber) + } + } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - logs, err1 := th.ORM.SelectLogsDataWordBetween(ctx, address, eventSig, 0, 1, logpoller.EvmWord(tt.wordValue), evmtypes.Unconfirmed) - assert.NoError(t, err1) - assert.Len(t, logs, len(tt.expectedLogs)) + logs, err := th.ORM.SelectLogsDataWordBetween(ctx, address, eventSig, 0, 1, logpoller.EvmWord(tt.wordValue), evmtypes.Unconfirmed) - for index := range logs { - assert.Equal(t, tt.expectedLogs[index], logs[index].BlockNumber) - } + assertion(t, logs, err, tt.expectedLogs) + + logs, err = th.ORM.FilteredLogs(ctx, wordFilter(tt.wordValue), limiter, "") + + assertion(t, logs, err, tt.expectedLogs) }) } } diff --git a/core/chains/evm/logpoller/parser.go b/core/chains/evm/logpoller/parser.go new file mode 100644 index 00000000000..1fe9bcde7d5 --- /dev/null +++ b/core/chains/evm/logpoller/parser.go @@ -0,0 +1,502 @@ +package logpoller + +import ( + "errors" + "fmt" + "math/big" + "strconv" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/smartcontractkit/chainlink-common/pkg/types/query" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" +) + +const ( + blockFieldName = "block_number" + timestampFieldName = "block_timestamp" + txHashFieldName = "tx_hash" + eventSigFieldName = "event_sig" +) + +var ( + ErrUnexpectedCursorFormat = errors.New("unexpected cursor format") +) + +// The parser builds SQL expressions piece by piece for each Accept function call and resets the error and expression +// values after every call. +type pgDSLParser struct { + args *queryArgs + + // transient properties expected to be set and reset with every expression + expression string + err error +} + +var _ primitives.Visitor = (*pgDSLParser)(nil) + +func (v *pgDSLParser) Comparator(_ primitives.Comparator) {} + +func (v *pgDSLParser) Block(p primitives.Block) { + cmp, err := cmpOpToString(p.Operator) + if err != nil { + v.err = err + + return + } + + v.expression = fmt.Sprintf( + "%s %s :%s", + blockFieldName, + cmp, + v.args.withIndexedField(blockFieldName, p.Block), + ) +} + +func (v *pgDSLParser) Confirmations(p primitives.Confirmations) { + switch p.ConfirmationLevel { + case primitives.Finalized: + v.expression = v.nestedConfQuery(true, 0) + case primitives.Unconfirmed: + // Unconfirmed in the evm relayer is an alias to the case of 0 confirmations + // set the level to the number 0 and fallthrough to the default case + p.ConfirmationLevel = primitives.ConfirmationLevel(0) + + fallthrough + default: + // the default case passes the confirmation level as a number directly to a subquery + v.expression = v.nestedConfQuery(false, uint64(evmtypes.Confirmations(p.ConfirmationLevel))) + } +} + +func (v *pgDSLParser) Timestamp(p primitives.Timestamp) { + cmp, err := cmpOpToString(p.Operator) + if err != nil { + v.err = err + + return + } + + v.expression = fmt.Sprintf( + "%s %s :%s", + timestampFieldName, + cmp, + v.args.withIndexedField(timestampFieldName, time.Unix(int64(p.Timestamp), 0)), + ) +} + +func (v *pgDSLParser) TxHash(p primitives.TxHash) { + bts, err := hexutil.Decode(p.TxHash) + if errors.Is(err, hexutil.ErrMissingPrefix) { + bts, err = hexutil.Decode("0x" + p.TxHash) + } + + if err != nil { + v.err = err + + return + } + + txHash := common.BytesToHash(bts) + + v.expression = fmt.Sprintf( + "%s = :%s", + txHashFieldName, + v.args.withIndexedField(txHashFieldName, txHash), + ) +} + +func (v *pgDSLParser) VisitAddressFilter(p *addressFilter) { + v.expression = fmt.Sprintf( + "address = :%s", + v.args.withIndexedField("address", p.address), + ) +} + +func (v *pgDSLParser) VisitEventSigFilter(p *eventSigFilter) { + v.expression = fmt.Sprintf( + "%s = :%s", + eventSigFieldName, + v.args.withIndexedField(eventSigFieldName, p.eventSig), + ) +} + +func (v *pgDSLParser) nestedConfQuery(finalized bool, confs uint64) string { + var ( + from = "FROM evm.log_poller_blocks " + where = "WHERE evm_chain_id = :evm_chain_id " + order = "ORDER BY block_number DESC LIMIT 1" + selector string + ) + + if finalized { + selector = "SELECT finalized_block_number " + } else { + selector = fmt.Sprintf("SELECT greatest(block_number - :%s, 0) ", + v.args.withIndexedField("confs", confs), + ) + } + + var builder strings.Builder + + builder.WriteString(selector) + builder.WriteString(from) + builder.WriteString(where) + builder.WriteString(order) + + return fmt.Sprintf("%s <= (%s)", blockFieldName, builder.String()) +} + +func (v *pgDSLParser) VisitEventByWordFilter(p *eventByWordFilter) { + if len(p.ValueComparers) > 0 { + wordIdx := v.args.withIndexedField("word_index", p.WordIndex) + + comps := make([]string, len(p.ValueComparers)) + for idx, comp := range p.ValueComparers { + comps[idx], v.err = makeComp(comp, v.args, "word_value", wordIdx, "substring(data from 32*:%s+1 for 32) %s :%s") + if v.err != nil { + return + } + } + + v.expression = strings.Join(comps, " AND ") + } +} + +func (v *pgDSLParser) VisitEventTopicsByValueFilter(p *eventByTopicFilter) { + if len(p.ValueComparers) > 0 { + if !(p.Topic == 1 || p.Topic == 2 || p.Topic == 3) { + v.err = fmt.Errorf("invalid index for topic: %d", p.Topic) + + return + } + + // Add 1 since postgresql arrays are 1-indexed. + topicIdx := v.args.withIndexedField("topic_index", p.Topic+1) + + comps := make([]string, len(p.ValueComparers)) + for idx, comp := range p.ValueComparers { + comps[idx], v.err = makeComp(comp, v.args, "topic_value", topicIdx, "topics[:%s] %s :%s") + if v.err != nil { + return + } + } + + v.expression = strings.Join(comps, " AND ") + } +} + +func makeComp(comp primitives.ValueComparator, args *queryArgs, field, subfield, pattern string) (string, error) { + cmp, err := cmpOpToString(comp.Operator) + if err != nil { + return "", err + } + + return fmt.Sprintf( + pattern, + subfield, + cmp, + args.withIndexedField(field, common.HexToHash(comp.Value)), + ), nil +} + +func (v *pgDSLParser) buildQuery(chainID *big.Int, expressions []query.Expression, limiter query.LimitAndSort) (string, *queryArgs, error) { + // reset transient properties + v.args = newQueryArgs(chainID) + v.expression = "" + v.err = nil + + // build the query string + clauses := []string{"SELECT evm.logs.* FROM evm.logs"} + + where, err := v.whereClause(expressions, limiter) + if err != nil { + return "", nil, err + } + + clauses = append(clauses, where) + + order, err := v.orderClause(limiter) + if err != nil { + return "", nil, err + } + + if len(order) > 0 { + clauses = append(clauses, order) + } + + limit := v.limitClause(limiter) + if len(limit) > 0 { + clauses = append(clauses, limit) + } + + return strings.Join(clauses, " "), v.args, nil +} + +func (v *pgDSLParser) whereClause(expressions []query.Expression, limiter query.LimitAndSort) (string, error) { + segment := "WHERE evm_chain_id = :evm_chain_id" + + if len(expressions) > 0 { + exp, err := v.combineExpressions(expressions, query.AND) + if err != nil { + return "", err + } + + segment = fmt.Sprintf("%s AND %s", segment, exp) + } + + if limiter.HasCursorLimit() { + var op string + switch limiter.Limit.CursorDirection { + case query.CursorFollowing: + op = ">" + case query.CursorPrevious: + op = "<" + default: + return "", errors.New("invalid cursor direction") + } + + block, txHash, logIdx, err := valuesFromCursor(limiter.Limit.Cursor) + if err != nil { + return "", err + } + + segment = fmt.Sprintf("%s AND block_number %s= :cursor_block AND tx_hash %s= :cursor_txhash AND log_index %s :cursor_log_index", segment, op, op, op) + + v.args.withField("cursor_block_number", block). + withField("cursor_txhash", common.HexToHash(txHash)). + withField("cursor_log_index", logIdx) + } + + return segment, nil +} + +func (v *pgDSLParser) orderClause(limiter query.LimitAndSort) (string, error) { + sorting := limiter.SortBy + + if limiter.HasCursorLimit() && !limiter.HasSequenceSort() { + var dir query.SortDirection + + switch limiter.Limit.CursorDirection { + case query.CursorFollowing: + dir = query.Asc + case query.CursorPrevious: + dir = query.Desc + default: + return "", errors.New("unexpected cursor direction") + } + + sorting = append(sorting, query.NewSortBySequence(dir)) + } + + if len(sorting) == 0 { + return "", nil + } + + sort := make([]string, len(sorting)) + + for idx, sorted := range sorting { + var name string + + order, err := orderToString(sorted.GetDirection()) + if err != nil { + return "", err + } + + switch sorted.(type) { + case query.SortByBlock: + name = blockFieldName + case query.SortBySequence: + sort[idx] = fmt.Sprintf("block_number %s, tx_hash %s, log_index %s", order, order, order) + + continue + case query.SortByTimestamp: + name = timestampFieldName + default: + return "", errors.New("unexpected sort by") + } + + sort[idx] = fmt.Sprintf("%s %s", name, order) + } + + return fmt.Sprintf("ORDER BY %s", strings.Join(sort, ", ")), nil +} + +func (v *pgDSLParser) limitClause(limiter query.LimitAndSort) string { + if !limiter.HasCursorLimit() && limiter.Limit.Count == 0 { + return "" + } + + return fmt.Sprintf("LIMIT %d", limiter.Limit.Count) +} + +func (v *pgDSLParser) getLastExpression() (string, error) { + exp := v.expression + err := v.err + + v.expression = "" + v.err = nil + + return exp, err +} + +func (v *pgDSLParser) combineExpressions(expressions []query.Expression, op query.BoolOperator) (string, error) { + grouped := len(expressions) > 1 + clauses := make([]string, len(expressions)) + + for idx, exp := range expressions { + if exp.IsPrimitive() { + exp.Primitive.Accept(v) + + clause, err := v.getLastExpression() + if err != nil { + return "", err + } + + clauses[idx] = clause + } else { + clause, err := v.combineExpressions(exp.BoolExpression.Expressions, exp.BoolExpression.BoolOperator) + if err != nil { + return "", err + } + + clauses[idx] = clause + } + } + + output := strings.Join(clauses, fmt.Sprintf(" %s ", op.String())) + + if grouped { + output = fmt.Sprintf("(%s)", output) + } + + return output, nil +} + +func cmpOpToString(op primitives.ComparisonOperator) (string, error) { + switch op { + case primitives.Eq: + return "=", nil + case primitives.Neq: + return "!=", nil + case primitives.Gt: + return ">", nil + case primitives.Gte: + return ">=", nil + case primitives.Lt: + return "<", nil + case primitives.Lte: + return "<=", nil + default: + return "", errors.New("invalid comparison operator") + } +} + +func orderToString(dir query.SortDirection) (string, error) { + switch dir { + case query.Asc: + return "ASC", nil + case query.Desc: + return "DESC", nil + default: + return "", errors.New("invalid sort direction") + } +} + +func valuesFromCursor(cursor string) (int64, string, int, error) { + parts := strings.Split(cursor, "-") + if len(parts) != 3 { + return 0, "", 0, fmt.Errorf("%w: must be composed as block-txhash-logindex", ErrUnexpectedCursorFormat) + } + + block, err := strconv.ParseInt(parts[0], 10, 64) + if err != nil { + return 0, "", 0, fmt.Errorf("%w: block number not parsable as int64", ErrUnexpectedCursorFormat) + } + + logIdx, err := strconv.ParseInt(parts[2], 10, 32) + if err != nil { + return 0, "", 0, fmt.Errorf("%w: log index not parsable as int", ErrUnexpectedCursorFormat) + } + + return block, parts[1], int(logIdx), nil +} + +type addressFilter struct { + address common.Address +} + +func NewAddressFilter(address common.Address) query.Expression { + return query.Expression{ + Primitive: &addressFilter{address: address}, + } +} + +func (f *addressFilter) Accept(visitor primitives.Visitor) { + switch v := visitor.(type) { + case *pgDSLParser: + v.VisitAddressFilter(f) + } +} + +type eventSigFilter struct { + eventSig common.Hash +} + +func NewEventSigFilter(hash common.Hash) query.Expression { + return query.Expression{ + Primitive: &eventSigFilter{eventSig: hash}, + } +} + +func (f *eventSigFilter) Accept(visitor primitives.Visitor) { + switch v := visitor.(type) { + case *pgDSLParser: + v.VisitEventSigFilter(f) + } +} + +type eventByWordFilter struct { + EventSig common.Hash + WordIndex uint8 + ValueComparers []primitives.ValueComparator +} + +func NewEventByWordFilter(eventSig common.Hash, wordIndex uint8, valueComparers []primitives.ValueComparator) query.Expression { + return query.Expression{Primitive: &eventByWordFilter{ + EventSig: eventSig, + WordIndex: wordIndex, + ValueComparers: valueComparers, + }} +} + +func (f *eventByWordFilter) Accept(visitor primitives.Visitor) { + switch v := visitor.(type) { + case *pgDSLParser: + v.VisitEventByWordFilter(f) + } +} + +type eventByTopicFilter struct { + Topic uint64 + ValueComparers []primitives.ValueComparator +} + +func NewEventByTopicFilter(topicIndex uint64, valueComparers []primitives.ValueComparator) query.Expression { + return query.Expression{Primitive: &eventByTopicFilter{ + Topic: topicIndex, + ValueComparers: valueComparers, + }} +} + +func (f *eventByTopicFilter) Accept(visitor primitives.Visitor) { + switch v := visitor.(type) { + case *pgDSLParser: + v.VisitEventTopicsByValueFilter(f) + } +} diff --git a/core/chains/evm/logpoller/parser_test.go b/core/chains/evm/logpoller/parser_test.go new file mode 100644 index 00000000000..a95f7fa7ae7 --- /dev/null +++ b/core/chains/evm/logpoller/parser_test.go @@ -0,0 +1,339 @@ +package logpoller + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/types/query" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" +) + +func assertArgs(t *testing.T, args *queryArgs, numVals int) { + values, err := args.toArgs() + + assert.Len(t, values, numVals) + assert.NoError(t, err) +} + +func TestDSLParser(t *testing.T) { + t.Parallel() + + t.Run("query with no filters no order and no limit", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{} + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + + require.NoError(t, err) + assert.Equal(t, "SELECT evm.logs.* FROM evm.logs WHERE evm_chain_id = :evm_chain_id", result) + + assertArgs(t, args, 1) + }) + + t.Run("query with cursor and no order by", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{ + NewAddressFilter(common.HexToAddress("0x42")), + NewEventSigFilter(common.HexToHash("0x21")), + } + limiter := query.NewLimitAndSort(query.CursorLimit("10-0x42-5", query.CursorFollowing, 20)) + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND (address = :address_0 AND event_sig = :event_sig_0) " + + "AND block_number >= :cursor_block AND tx_hash >= :cursor_txhash AND log_index > :cursor_log_index " + + "ORDER BY block_number ASC, tx_hash ASC, log_index ASC " + + "LIMIT 20" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 6) + }) + + t.Run("query with limit and no order by", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{ + NewAddressFilter(common.HexToAddress("0x42")), + NewEventSigFilter(common.HexToHash("0x21")), + } + limiter := query.NewLimitAndSort(query.CountLimit(20)) + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND (address = :address_0 AND event_sig = :event_sig_0) " + + "LIMIT 20" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 3) + }) + + t.Run("query with order by sequence no cursor no limit", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{} + limiter := query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Desc)) + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "ORDER BY block_number DESC, tx_hash DESC, log_index DESC" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 1) + }) + + t.Run("query with multiple order by no limit", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{} + limiter := query.NewLimitAndSort(query.Limit{}, query.NewSortByBlock(query.Asc), query.NewSortByTimestamp(query.Desc)) + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "ORDER BY block_number ASC, block_timestamp DESC" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 1) + }) + + t.Run("basic query with default primitives no order by and cursor", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{ + query.Timestamp(10, primitives.Eq), + query.TxHash(common.HexToHash("0x84").String()), + query.Block(99, primitives.Neq), + query.Confirmation(primitives.Finalized), + query.Confirmation(primitives.Unconfirmed), + } + limiter := query.NewLimitAndSort(query.CursorLimit("10-0x42-20", query.CursorPrevious, 20)) + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND (block_timestamp = :block_timestamp_0 " + + "AND tx_hash = :tx_hash_0 " + + "AND block_number != :block_number_0 " + + "AND block_number <= " + + "(SELECT finalized_block_number FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1) " + + "AND block_number <= (SELECT greatest(block_number - :confs_0, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1)) " + + "AND block_number <= :cursor_block AND tx_hash <= :cursor_txhash AND log_index < :cursor_log_index " + + "ORDER BY block_number DESC, tx_hash DESC, log_index DESC LIMIT 20" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 8) + }) + + t.Run("query for finality", func(t *testing.T) { + t.Parallel() + + t.Run("finalized", func(t *testing.T) { + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{query.Confirmation(primitives.Finalized)} + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND block_number <= (SELECT finalized_block_number FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1)" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 1) + }) + + t.Run("unconfirmed", func(t *testing.T) { + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{query.Confirmation(primitives.Unconfirmed)} + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND block_number <= (SELECT greatest(block_number - :confs_0, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1)" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 2) + }) + }) + + t.Run("query for event by word", func(t *testing.T) { + t.Parallel() + + wordFilter := NewEventByWordFilter(common.HexToHash("0x42"), 8, []primitives.ValueComparator{ + {Value: "", Operator: primitives.Gt}, + }) + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{wordFilter} + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND substring(data from 32*:word_index_0+1 for 32) > :word_value_0" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 3) + }) + + t.Run("query for event topic", func(t *testing.T) { + t.Parallel() + + topicFilter := NewEventByTopicFilter(2, []primitives.ValueComparator{ + {Value: "a", Operator: primitives.Gt}, + {Value: "b", Operator: primitives.Lt}, + }) + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{topicFilter} + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND topics[:topic_index_0] > :topic_value_0 AND topics[:topic_index_0] < :topic_value_1" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 4) + }) + + // nested query -> a & (b || c) + t.Run("nested query", func(t *testing.T) { + t.Parallel() + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{ + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.Timestamp(10, primitives.Gte), + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.TxHash(common.HexToHash("0x84").Hex()), + query.Confirmation(primitives.Unconfirmed), + }, + BoolOperator: query.OR, + }}, + }, + BoolOperator: query.AND, + }}, + } + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND (block_timestamp >= :block_timestamp_0 " + + "AND (tx_hash = :tx_hash_0 " + + "OR block_number <= (SELECT greatest(block_number - :confs_0, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1)))" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 4) + }) + + // deep nested query -> a & (b || (c & d)) + t.Run("nested query deep", func(t *testing.T) { + t.Parallel() + + wordFilter := NewEventByWordFilter(common.HexToHash("0x42"), 8, []primitives.ValueComparator{ + {Value: "a", Operator: primitives.Gt}, + {Value: "b", Operator: primitives.Lte}, + }) + + parser := &pgDSLParser{} + chainID := big.NewInt(1) + expressions := []query.Expression{ + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.Timestamp(10, primitives.Eq), + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.TxHash(common.HexToHash("0x84").Hex()), + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + query.Confirmation(primitives.Unconfirmed), + wordFilter, + }, + BoolOperator: query.AND, + }}, + }, + BoolOperator: query.OR, + }}, + }, + BoolOperator: query.AND, + }}, + } + limiter := query.LimitAndSort{} + + result, args, err := parser.buildQuery(chainID, expressions, limiter) + expected := "SELECT evm.logs.* " + + "FROM evm.logs " + + "WHERE evm_chain_id = :evm_chain_id " + + "AND (block_timestamp = :block_timestamp_0 " + + "AND (tx_hash = :tx_hash_0 " + + "OR (block_number <= (SELECT greatest(block_number - :confs_0, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1) " + + "AND substring(data from 32*:word_index_0+1 for 32) > :word_value_0 " + + "AND substring(data from 32*:word_index_0+1 for 32) <= :word_value_1)))" + + require.NoError(t, err) + assert.Equal(t, expected, result) + + assertArgs(t, args, 7) + }) +} diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go index 244552dbec8..b39a260f034 100644 --- a/core/chains/evm/logpoller/query.go +++ b/core/chains/evm/logpoller/query.go @@ -28,16 +28,18 @@ func concatBytes[T bytesProducer](byteSlice []T) [][]byte { // queryArgs is a helper for building the arguments to a postgres query created by DSORM // Besides the convenience methods, it also keeps track of arguments validation and sanitization. type queryArgs struct { - args map[string]interface{} - err []error + args map[string]any + idxLookup map[string]uint8 + err []error } func newQueryArgs(chainId *big.Int) *queryArgs { return &queryArgs{ - args: map[string]interface{}{ + args: map[string]any{ "evm_chain_id": ubig.New(chainId), }, - err: []error{}, + idxLookup: make(map[string]uint8), + err: []error{}, } } @@ -47,16 +49,62 @@ func newQueryArgsForEvent(chainId *big.Int, address common.Address, eventSig com withEventSig(eventSig) } +func (q *queryArgs) withField(fieldName string, value any) *queryArgs { + _, args := q.withIndexableField(fieldName, value, false) + + return args +} + +func (q *queryArgs) withIndexedField(fieldName string, value any) string { + field, _ := q.withIndexableField(fieldName, value, true) + + return field +} + +func (q *queryArgs) withIndexableField(fieldName string, value any, addIndex bool) (string, *queryArgs) { + if addIndex { + idx := q.nextIdx(fieldName) + idxName := fmt.Sprintf("%s_%d", fieldName, idx) + + q.idxLookup[fieldName] = uint8(idx) + fieldName = idxName + } + + switch typed := value.(type) { + case common.Hash: + q.args[fieldName] = typed.Bytes() + case []common.Hash: + q.args[fieldName] = concatBytes(typed) + case types.HashArray: + q.args[fieldName] = concatBytes(typed) + case []common.Address: + q.args[fieldName] = concatBytes(typed) + default: + q.args[fieldName] = typed + } + + return fieldName, q +} + +func (q *queryArgs) nextIdx(baseFieldName string) int { + idx, ok := q.idxLookup[baseFieldName] + if !ok { + return 0 + } + + return int(idx) + 1 +} + func (q *queryArgs) withEventSig(eventSig common.Hash) *queryArgs { - return q.withCustomHashArg("event_sig", eventSig) + return q.withField("event_sig", eventSig) } func (q *queryArgs) withEventSigArray(eventSigs []common.Hash) *queryArgs { - return q.withCustomArg("event_sig_array", concatBytes(eventSigs)) + return q.withField("event_sig_array", eventSigs) } func (q *queryArgs) withTopicArray(topicValues types.HashArray, topicNum uint64) *queryArgs { - return q.withCustomArg(fmt.Sprintf("topic%d", topicNum), concatBytes(topicValues)) + return q.withField(fmt.Sprintf("topic%d", topicNum), topicValues) } func (q *queryArgs) withTopicArrays(topic2Vals types.HashArray, topic3Vals types.HashArray, topic4Vals types.HashArray) *queryArgs { @@ -66,47 +114,47 @@ func (q *queryArgs) withTopicArrays(topic2Vals types.HashArray, topic3Vals types } func (q *queryArgs) withAddress(address common.Address) *queryArgs { - return q.withCustomArg("address", address) + return q.withField("address", address) } func (q *queryArgs) withAddressArray(addresses []common.Address) *queryArgs { - return q.withCustomArg("address_array", concatBytes(addresses)) + return q.withField("address_array", addresses) } func (q *queryArgs) withStartBlock(startBlock int64) *queryArgs { - return q.withCustomArg("start_block", startBlock) + return q.withField("start_block", startBlock) } func (q *queryArgs) withEndBlock(endBlock int64) *queryArgs { - return q.withCustomArg("end_block", endBlock) + return q.withField("end_block", endBlock) } func (q *queryArgs) withWordIndex(wordIndex int) *queryArgs { - return q.withCustomArg("word_index", wordIndex) + return q.withField("word_index", wordIndex) } func (q *queryArgs) withWordValueMin(wordValueMin common.Hash) *queryArgs { - return q.withCustomHashArg("word_value_min", wordValueMin) + return q.withField("word_value_min", wordValueMin) } func (q *queryArgs) withWordValueMax(wordValueMax common.Hash) *queryArgs { - return q.withCustomHashArg("word_value_max", wordValueMax) + return q.withField("word_value_max", wordValueMax) } func (q *queryArgs) withWordIndexMin(wordIndex int) *queryArgs { - return q.withCustomArg("word_index_min", wordIndex) + return q.withField("word_index_min", wordIndex) } func (q *queryArgs) withWordIndexMax(wordIndex int) *queryArgs { - return q.withCustomArg("word_index_max", wordIndex) + return q.withField("word_index_max", wordIndex) } func (q *queryArgs) withWordValue(wordValue common.Hash) *queryArgs { - return q.withCustomHashArg("word_value", wordValue) + return q.withField("word_value", wordValue) } func (q *queryArgs) withConfs(confs evmtypes.Confirmations) *queryArgs { - return q.withCustomArg("confs", confs) + return q.withField("confs", confs) } func (q *queryArgs) withTopicIndex(index int) *queryArgs { @@ -115,53 +163,45 @@ func (q *queryArgs) withTopicIndex(index int) *queryArgs { q.err = append(q.err, fmt.Errorf("invalid index for topic: %d", index)) } // Add 1 since postgresql arrays are 1-indexed. - return q.withCustomArg("topic_index", index+1) + return q.withField("topic_index", index+1) } func (q *queryArgs) withTopicValueMin(valueMin common.Hash) *queryArgs { - return q.withCustomHashArg("topic_value_min", valueMin) + return q.withField("topic_value_min", valueMin) } func (q *queryArgs) withTopicValueMax(valueMax common.Hash) *queryArgs { - return q.withCustomHashArg("topic_value_max", valueMax) + return q.withField("topic_value_max", valueMax) } func (q *queryArgs) withTopicValues(values []common.Hash) *queryArgs { - return q.withCustomArg("topic_values", concatBytes(values)) + return q.withField("topic_values", concatBytes(values)) } func (q *queryArgs) withBlockTimestampAfter(after time.Time) *queryArgs { - return q.withCustomArg("block_timestamp_after", after) + return q.withField("block_timestamp_after", after) } func (q *queryArgs) withTxHash(hash common.Hash) *queryArgs { - return q.withCustomHashArg("tx_hash", hash) + return q.withField("tx_hash", hash) } func (q *queryArgs) withRetention(retention time.Duration) *queryArgs { - return q.withCustomArg("retention", retention) + return q.withField("retention", retention) } func (q *queryArgs) withLogsPerBlock(logsPerBlock uint64) *queryArgs { - return q.withCustomArg("logs_per_block", logsPerBlock) + return q.withField("logs_per_block", logsPerBlock) } func (q *queryArgs) withMaxLogsKept(maxLogsKept uint64) *queryArgs { - return q.withCustomArg("max_logs_kept", maxLogsKept) + return q.withField("max_logs_kept", maxLogsKept) } -func (q *queryArgs) withCustomHashArg(name string, arg common.Hash) *queryArgs { - return q.withCustomArg(name, arg.Bytes()) -} - -func (q *queryArgs) withCustomArg(name string, arg any) *queryArgs { - q.args[name] = arg - return q -} - -func (q *queryArgs) toArgs() (map[string]interface{}, error) { +func (q *queryArgs) toArgs() (map[string]any, error) { if len(q.err) > 0 { return nil, errors.Join(q.err...) } + return q.args, nil } diff --git a/core/chains/evm/logpoller/query_test.go b/core/chains/evm/logpoller/query_test.go index 832cbbfcb00..67472ecead4 100644 --- a/core/chains/evm/logpoller/query_test.go +++ b/core/chains/evm/logpoller/query_test.go @@ -33,14 +33,14 @@ func Test_QueryArgs(t *testing.T) { }, { name: "custom argument", - queryArgs: newEmptyArgs().withCustomArg("arg", "value"), + queryArgs: newEmptyArgs().withField("arg", "value"), want: map[string]interface{}{ "arg": "value", }, }, { name: "hash converted to bytes", - queryArgs: newEmptyArgs().withCustomHashArg("hash", common.Hash{}), + queryArgs: newEmptyArgs().withField("hash", common.Hash{}), want: map[string]interface{}{ "hash": make([]byte, 32), }, diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index 85c837e55bc..4a8c3691d1a 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -12,7 +12,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/types/query" - "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -216,7 +215,7 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain inputInfo: inputInfo, inputModifier: inputModifier, codecTopicInfo: codecTopicInfo, - topicsInfo: make(map[string]topicInfo), + topics: make(map[string]topicDetail), eventDataWords: chainReaderDefinition.GenericDataWordNames, id: wrapItemType(contractName, eventName, false) + uuid.NewString(), } @@ -227,11 +226,12 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain for topicIndex, topic := range event.Inputs { genericTopicName, ok := chainReaderDefinition.GenericTopicNames[topic.Name] if ok { - eb.topicsInfo[genericTopicName] = topicInfo{ - Argument: topic, - topicIndex: uint64(topicIndex), + eb.topics[genericTopicName] = topicDetail{ + Argument: topic, + Index: uint64(topicIndex), } } + // this way querying by key/s values comparison can find its bindings cr.contractBindings.AddReadBinding(contractName, genericTopicName, eb) } @@ -296,56 +296,6 @@ func (cr *chainReader) addDecoderDef(contractName, itemType string, outputs abi. return output.Init() } -// remapFilter, changes chain agnostic filters to match evm specific filters. -func (e *eventBinding) remapFilter(filter query.KeyFilter) (remappedFilter query.KeyFilter, err error) { - addEventSigFilter := false - for _, expression := range filter.Expressions { - remappedExpression, hasComparatorPrimitive, err := e.remapExpression(filter.Key, expression) - if err != nil { - return query.KeyFilter{}, err - } - remappedFilter.Expressions = append(remappedFilter.Expressions, remappedExpression) - // comparator primitive maps to event by topic or event by evm data word filters, which means that event sig filter is not needed - addEventSigFilter = addEventSigFilter != hasComparatorPrimitive - } - - if addEventSigFilter { - remappedFilter.Expressions = append(remappedFilter.Expressions, NewEventBySigFilter(e.address, e.hash)) - } - return remappedFilter, nil -} - -func (e *eventBinding) remapExpression(key string, expression query.Expression) (remappedExpression query.Expression, hasComparerPrimitive bool, err error) { - if !expression.IsPrimitive() { - for i := range expression.BoolExpression.Expressions { - remappedExpression, hasComparerPrimitive, err = e.remapExpression(key, expression.BoolExpression.Expressions[i]) - if err != nil { - return query.Expression{}, false, err - } - remappedExpression.BoolExpression.Expressions = append(remappedExpression.BoolExpression.Expressions, remappedExpression) - } - - if expression.BoolExpression.BoolOperator == query.AND { - return query.And(remappedExpression.BoolExpression.Expressions...), hasComparerPrimitive, nil - } - return query.Or(remappedExpression.BoolExpression.Expressions...), hasComparerPrimitive, nil - } - - // remap chain agnostic primitives to chain specific - switch primitive := expression.Primitive.(type) { - case *primitives.Confirmations: - remappedExpression, err = NewFinalityFilter(primitive) - return remappedExpression, hasComparerPrimitive, err - case *primitives.Comparator: - if val, ok := e.eventDataWords[primitive.Name]; ok { - return NewEventByWordFilter(e.hash, val, primitive.ValueComparators), true, nil - } - return NewEventByTopicFilter(e.hash, e.topicsInfo[key].topicIndex, primitive.ValueComparators), true, nil - default: - return expression, hasComparerPrimitive, nil - } -} - func setupEventInput(event abi.Event, def types.ChainReaderDefinition) ([]abi.Argument, types.CodecEntry, map[string]bool) { topicFieldDefs := map[string]bool{} for _, value := range def.EventInputFields { diff --git a/core/services/relay/evm/chain_reader_test.go b/core/services/relay/evm/chain_reader_test.go index c3cb36b93e3..72332f38a06 100644 --- a/core/services/relay/evm/chain_reader_test.go +++ b/core/services/relay/evm/chain_reader_test.go @@ -49,6 +49,7 @@ const ( func TestChainReaderGetLatestValue(t *testing.T) { t.Parallel() it := &chainReaderInterfaceTester{} + RunChainReaderGetLatestValueInterfaceTests(t, it) RunChainReaderGetLatestValueInterfaceTests(t, commontestutils.WrapChainReaderTesterForLoop(it)) @@ -109,6 +110,14 @@ func TestChainReaderGetLatestValue(t *testing.T) { }) } +func TestChainReaderQueryKey(t *testing.T) { + t.Parallel() + it := &chainReaderInterfaceTester{} + + RunQueryKeyInterfaceTests(t, it) + RunQueryKeyInterfaceTests(t, commontestutils.WrapChainReaderTesterForLoop(it)) +} + func triggerFourTopics(t *testing.T, it *chainReaderInterfaceTester, i1, i2, i3 int32) { tx, err := it.evmTest.ChainReaderTesterTransactor.TriggerWithFourTopics(it.auth, i1, i2, i3) require.NoError(t, err) diff --git a/core/services/relay/evm/dsl.go b/core/services/relay/evm/dsl.go deleted file mode 100644 index 05592feb996..00000000000 --- a/core/services/relay/evm/dsl.go +++ /dev/null @@ -1,96 +0,0 @@ -package evm - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink-common/pkg/types/query" - "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" -) - -type EventBySigFilter struct { - Address common.Address - EventSig common.Hash -} - -func NewEventBySigFilter(address common.Address, eventSig common.Hash) query.Expression { - var searchEventFilter *EventBySigFilter - searchEventFilter.Address = address - searchEventFilter.EventSig = eventSig - return query.Expression{Primitive: searchEventFilter} -} - -func (f *EventBySigFilter) Accept(visitor primitives.Visitor) { - switch v := visitor.(type) { - case *PgDSLParser: - v.VisitEventBySigFilter(f) - } -} - -type EventByTopicFilter struct { - EventSig common.Hash - Topic uint64 - ValueComparators []primitives.ValueComparator -} - -func NewEventByTopicFilter(eventSig common.Hash, topicIndex uint64, valueComparators []primitives.ValueComparator) query.Expression { - var eventByIndexFilter *EventByTopicFilter - eventByIndexFilter.EventSig = eventSig - eventByIndexFilter.Topic = topicIndex - eventByIndexFilter.ValueComparators = valueComparators - - return query.Expression{Primitive: eventByIndexFilter} -} - -func (f *EventByTopicFilter) Accept(visitor primitives.Visitor) { - switch v := visitor.(type) { - case *PgDSLParser: - v.VisitEventTopicsByValueFilter(f) - } -} - -type EventByWordFilter struct { - EventSig common.Hash - WordIndex uint8 - ValueComparators []primitives.ValueComparator -} - -func NewEventByWordFilter(eventSig common.Hash, wordIndex uint8, valueComparators []primitives.ValueComparator) query.Expression { - var eventByIndexFilter *EventByWordFilter - eventByIndexFilter.EventSig = eventSig - eventByIndexFilter.WordIndex = wordIndex - eventByIndexFilter.ValueComparators = valueComparators - return query.Expression{Primitive: eventByIndexFilter} -} - -func (f *EventByWordFilter) Accept(visitor primitives.Visitor) { - switch v := visitor.(type) { - case *PgDSLParser: - v.VisitEventByWordFilter(f) - } -} - -type FinalityFilter struct { - Confs evmtypes.Confirmations -} - -func NewFinalityFilter(filter *primitives.Confirmations) (query.Expression, error) { - // TODO chain agnostic confidence levels that map to evm finality - switch filter.ConfirmationLevel { - case primitives.Finalized: - return query.Expression{Primitive: &FinalityFilter{evmtypes.Finalized}}, nil - case primitives.Unconfirmed: - return query.Expression{Primitive: &FinalityFilter{evmtypes.Unconfirmed}}, nil - default: - return query.Expression{}, fmt.Errorf("invalid finality confirmations filter value %v", filter.ConfirmationLevel) - } -} - -func (f *FinalityFilter) Accept(visitor primitives.Visitor) { - switch v := visitor.(type) { - case *PgDSLParser: - v.VisitFinalityFilter(f) - } -} diff --git a/core/services/relay/evm/event_binding.go b/core/services/relay/evm/event_binding.go index f43576de4ff..98903f1463d 100644 --- a/core/services/relay/evm/event_binding.go +++ b/core/services/relay/evm/event_binding.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/codec" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/query" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -33,48 +34,22 @@ type eventBinding struct { inputInfo types.CodecEntry inputModifier codec.Modifier codecTopicInfo types.CodecEntry - // key is generic topic name - topicsInfo map[string]topicInfo + // topics maps a generic topic name (key) to topic data + topics map[string]topicDetail + // eventDataWords maps a generic name to a word index // key is a predefined generic name for evm log event data word // for eg. first evm data word(32bytes) of USDC log event is value so the key can be called value eventDataWords map[string]uint8 - // used to allow Register and Unregister to be unique in case two bindings have the same event. - // otherwise, if one unregisters, it'll unregister both with the LogPoller. - id string + id string } -type topicInfo struct { +type topicDetail struct { abi.Argument - topicIndex uint64 + Index uint64 } var _ readBinding = &eventBinding{} -func (e *eventBinding) decodeLogsIntoSequences(ctx context.Context, logs []logpoller.Log, into any) ([]commontypes.Sequence, error) { - var sequences []commontypes.Sequence - for i := range logs { - sequence := commontypes.Sequence{ - // TODO SequenceCursor, should be combination of block, eventsig, topic and also match a proper db cursor?... - Cursor: "TODO", - Head: commontypes.Head{ - Identifier: fmt.Sprint(logs[i].BlockNumber), - Hash: logs[i].BlockHash.Bytes(), - Timestamp: uint64(logs[i].BlockTimestamp.Unix()), - }, - // TODO test this - Data: reflect.New(reflect.TypeOf(into).Elem()), - } - - if err := e.decodeLog(ctx, &logs[i], sequence.Data); err != nil { - return nil, err - } - - sequences = append(sequences, sequence) - } - - return sequences, nil -} - func (e *eventBinding) SetCodec(codec commontypes.RemoteCodec) { e.codec = codec } @@ -130,16 +105,32 @@ func (e *eventBinding) GetLatestValue(ctx context.Context, params, into any) err } func (e *eventBinding) QueryKey(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]commontypes.Sequence, error) { - remappedFilter, err := e.remapFilter(filter) + if !e.bound { + return nil, fmt.Errorf("%w: event not bound", commontypes.ErrInvalidType) + } + + remapped, err := e.remap(filter) if err != nil { return nil, err } - logs, err := e.lp.FilteredLogs(remappedFilter, limitAndSort) + // filter should always use the address and event sig + defaultExpressions := []query.Expression{ + logpoller.NewAddressFilter(e.address), + logpoller.NewEventSigFilter(e.hash), + } + remapped.Expressions = append(defaultExpressions, remapped.Expressions...) + + logs, err := e.lp.FilteredLogs(ctx, remapped, limitAndSort, e.contractName+"-"+e.eventName) if err != nil { return nil, err } + // no need to return an error. an empty list is fine + if len(logs) == 0 { + return []commontypes.Sequence{}, nil + } + return e.decodeLogsIntoSequences(ctx, logs, sequenceDataType) } @@ -326,6 +317,91 @@ func (e *eventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into a return mapstructureDecode(topicsInto, into) } +func (e *eventBinding) decodeLogsIntoSequences(ctx context.Context, logs []logpoller.Log, into any) ([]commontypes.Sequence, error) { + sequences := make([]commontypes.Sequence, len(logs)) + + for idx := range logs { + sequences[idx] = commontypes.Sequence{ + Cursor: fmt.Sprintf("%s-%s-%d", logs[idx].BlockHash, logs[idx].TxHash, logs[idx].LogIndex), + Head: commontypes.Head{ + Identifier: fmt.Sprint(logs[idx].BlockNumber), + Hash: logs[idx].BlockHash.Bytes(), + Timestamp: uint64(logs[idx].BlockTimestamp.Unix()), + }, + } + + var typeVal reflect.Value + + typeInto := reflect.TypeOf(into) + if typeInto.Kind() == reflect.Pointer { + typeVal = reflect.New(typeInto.Elem()) + } else { + typeVal = reflect.Indirect(reflect.New(typeInto)) + } + + // create a new value of the same type as 'into' for the data to be extracted to + sequences[idx].Data = typeVal.Interface() + + if err := e.decodeLog(ctx, &logs[idx], sequences[idx].Data); err != nil { + return nil, err + } + } + + return sequences, nil +} + +func (e *eventBinding) remap(filter query.KeyFilter) (query.KeyFilter, error) { + remapped := query.KeyFilter{} + + for _, expression := range filter.Expressions { + remappedExpression, err := e.remapExpression(filter.Key, expression) + if err != nil { + return query.KeyFilter{}, err + } + + remapped.Expressions = append(remapped.Expressions, remappedExpression) + } + + return remapped, nil +} + +func (e *eventBinding) remapExpression(key string, expression query.Expression) (query.Expression, error) { + if !expression.IsPrimitive() { + remappedBoolExpressions := make([]query.Expression, len(expression.BoolExpression.Expressions)) + + for i := range expression.BoolExpression.Expressions { + remapped, err := e.remapExpression(key, expression.BoolExpression.Expressions[i]) + if err != nil { + return query.Expression{}, err + } + + remappedBoolExpressions[i] = remapped + } + + if expression.BoolExpression.BoolOperator == query.AND { + return query.And(remappedBoolExpressions...), nil + } + + return query.Or(remappedBoolExpressions...), nil + } + + return e.remapPrimitive(key, expression) +} + +// remap chain agnostic primitives to chain specific +func (e *eventBinding) remapPrimitive(key string, expression query.Expression) (query.Expression, error) { + switch primitive := expression.Primitive.(type) { + case *primitives.Comparator: + if val, ok := e.eventDataWords[primitive.Name]; ok { + return logpoller.NewEventByWordFilter(e.hash, val, primitive.ValueComparators), nil + } + + return logpoller.NewEventByTopicFilter(e.topics[key].Index, primitive.ValueComparators), nil + default: + return expression, nil + } +} + func wrapInternalErr(err error) error { if err == nil { return nil diff --git a/core/services/relay/evm/pgparser.go b/core/services/relay/evm/pgparser.go deleted file mode 100644 index 62e95c10121..00000000000 --- a/core/services/relay/evm/pgparser.go +++ /dev/null @@ -1,36 +0,0 @@ -package evm - -import ( - "math/big" - - "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" -) - -// PgDSLParser is a visitor that builds a postgres query and arguments from a query.KeyFilter -type PgDSLParser struct { - //TODO implement psql parser -} - -var _ primitives.Visitor = (*PgDSLParser)(nil) - -func NewPgParser(evmChainID *big.Int) *PgDSLParser { - return &PgDSLParser{} -} - -func (v *PgDSLParser) Comparator(_ primitives.Comparator) {} - -func (v *PgDSLParser) Block(_ primitives.Block) {} - -func (v *PgDSLParser) Confirmations(_ primitives.Confirmations) {} - -func (v *PgDSLParser) Timestamp(_ primitives.Timestamp) {} - -func (v *PgDSLParser) TxHash(_ primitives.TxHash) {} - -func (v *PgDSLParser) VisitEventTopicsByValueFilter(_ *EventByTopicFilter) {} - -func (v *PgDSLParser) VisitEventByWordFilter(_ *EventByWordFilter) {} - -func (v *PgDSLParser) VisitEventBySigFilter(_ *EventBySigFilter) {} - -func (v *PgDSLParser) VisitFinalityFilter(_ *FinalityFilter) {} From 49f1bf3ba296f0e3dfc01d5a3d371f82f159dc4a Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 16 May 2024 06:49:12 -0500 Subject: [PATCH 17/17] pg connection cleanup (#13144) --- .changeset/big-windows-lie.md | 5 ++ .golangci.yml | 4 ++ core/internal/testutils/pgtest/txdb.go | 2 +- core/services/pg/connection.go | 74 ++++++++++++++++---------- go.mod | 4 +- 5 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 .changeset/big-windows-lie.md diff --git a/.changeset/big-windows-lie.md b/.changeset/big-windows-lie.md new file mode 100644 index 00000000000..aa81a75c6ee --- /dev/null +++ b/.changeset/big-windows-lie.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +improve handling of postgres connection settings and driver versions #db diff --git a/.golangci.yml b/.golangci.yml index 2902503ed20..96a7de282e0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -89,6 +89,10 @@ linters-settings: desc: Use the standard library instead - pkg: github.com/gofrs/uuid desc: Use github.com/google/uuid instead + - pkg: github.com/jackc/pgx3 + desc: Use github.com/jackc/pgx4 instead + - pkg: github.com/jackc/pgx5 + desc: Use github.com/jackc/pgx4 instead - pkg: github.com/satori/go.uuid desc: Use github.com/google/uuid instead - pkg: github.com/test-go/testify/assert diff --git a/core/internal/testutils/pgtest/txdb.go b/core/internal/testutils/pgtest/txdb.go index f4640946ad4..7591054305c 100644 --- a/core/internal/testutils/pgtest/txdb.go +++ b/core/internal/testutils/pgtest/txdb.go @@ -89,7 +89,7 @@ func (d *txDriver) Open(dsn string) (driver.Conn, error) { defer d.Unlock() // Open real db connection if its the first call if d.db == nil { - db, err := sql.Open("pgx", d.dbURL) + db, err := sql.Open(string(dialects.Postgres), d.dbURL) if err != nil { return nil, err } diff --git a/core/services/pg/connection.go b/core/services/pg/connection.go index e8b6f3af429..b76c9bc10ed 100644 --- a/core/services/pg/connection.go +++ b/core/services/pg/connection.go @@ -7,16 +7,17 @@ import ( "os" "time" + "github.com/XSAM/otelsql" "github.com/google/uuid" - _ "github.com/jackc/pgx/v4/stdlib" // need to make sure pgx driver is registered before opening connection + "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v4/stdlib" "github.com/jmoiron/sqlx" "github.com/scylladb/go-reflectx" "go.opentelemetry.io/otel" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + "golang.org/x/net/context" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" - - "github.com/XSAM/otelsql" ) // NOTE: This is the default level in Postgres anyway, we just make it @@ -48,21 +49,8 @@ type ConnectionConfig interface { MaxIdleConns() int } -func NewConnection(uri string, dialect dialects.DialectName, config ConnectionConfig) (db *sqlx.DB, err error) { - if dialect == dialects.TransactionWrappedPostgres { - // Dbtx uses the uri as a unique identifier for each transaction. Each ORM - // should be encapsulated in it's own transaction, and thus needs its own - // unique id. - // - // We can happily throw away the original uri here because if we are using - // txdb it should have already been set at the point where we called - // txdb.Register - uri = uuid.New().String() - } - - // Initialize sql/sqlx - sqldb, err := otelsql.Open(string(dialect), uri, - otelsql.WithAttributes(semconv.DBSystemPostgreSQL), +func NewConnection(uri string, dialect dialects.DialectName, config ConnectionConfig) (*sqlx.DB, error) { + opts := []otelsql.Option{otelsql.WithAttributes(semconv.DBSystemPostgreSQL), otelsql.WithTracerProvider(otel.GetTracerProvider()), otelsql.WithSQLCommenter(true), otelsql.WithSpanOptions(otelsql.SpanOptions{ @@ -71,22 +59,52 @@ func NewConnection(uri string, dialect dialects.DialectName, config ConnectionCo OmitRows: true, OmitConnectorConnect: true, OmitConnQuery: false, - }), - ) - if err != nil { - return nil, err - } - db = sqlx.NewDb(sqldb, string(dialect)) - db.MapperFunc(reflectx.CamelToSnakeASCII) + })} // Set default connection options lockTimeout := config.DefaultLockTimeout().Milliseconds() idleInTxSessionTimeout := config.DefaultIdleInTxSessionTimeout().Milliseconds() - stmt := fmt.Sprintf(`SET TIME ZONE 'UTC'; SET lock_timeout = %d; SET idle_in_transaction_session_timeout = %d; SET default_transaction_isolation = %q`, + connParams := fmt.Sprintf(`SET TIME ZONE 'UTC'; SET lock_timeout = %d; SET idle_in_transaction_session_timeout = %d; SET default_transaction_isolation = %q`, lockTimeout, idleInTxSessionTimeout, defaultIsolation.String()) - if _, err = db.Exec(stmt); err != nil { - return nil, err + + var sqldb *sql.DB + if dialect == dialects.TransactionWrappedPostgres { + // Dbtx uses the uri as a unique identifier for each transaction. Each ORM + // should be encapsulated in it's own transaction, and thus needs its own + // unique id. + // + // We can happily throw away the original uri here because if we are using + // txdb it should have already been set at the point where we called + // txdb.Register + var err error + sqldb, err = otelsql.Open(string(dialect), uuid.New().String(), opts...) + if err != nil { + return nil, fmt.Errorf("failed to open txdb: %w", err) + } + _, err = sqldb.Exec(connParams) + if err != nil { + return nil, fmt.Errorf("failed to set options: %w", err) + } + } else { + // Set sane defaults for every new database connection. + // Those can be overridden with Txn options or SET statements in individual connections. + // The default values are the same for Txns. + connConfig, err := pgx.ParseConfig(uri) + if err != nil { + return nil, fmt.Errorf("database: failed to parse config: %w", err) + } + + connector := stdlib.GetConnector(*connConfig, stdlib.OptionAfterConnect(func(ctx context.Context, c *pgx.Conn) (err error) { + _, err = c.Exec(ctx, connParams) + return + })) + + // Initialize sql/sqlx + sqldb = otelsql.OpenDB(connector, opts...) } + db := sqlx.NewDb(sqldb, string(dialect)) + db.MapperFunc(reflectx.CamelToSnakeASCII) + setMaxConns(db, config) if os.Getenv("SKIP_PG_VERSION_CHECK") != "true" { diff --git a/go.mod b/go.mod index 4250c0fef43..f46e4b78333 100644 --- a/go.mod +++ b/go.mod @@ -101,6 +101,7 @@ require ( golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/mod v0.15.0 + golang.org/x/net v0.24.0 golang.org/x/sync v0.6.0 golang.org/x/term v0.19.0 golang.org/x/text v0.14.0 @@ -111,6 +112,7 @@ require ( google.golang.org/protobuf v1.33.0 gopkg.in/guregu/null.v4 v4.0.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 + sigs.k8s.io/yaml v1.4.0 ) require ( @@ -324,7 +326,6 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.3.0 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.19.0 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect @@ -336,7 +337,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect pgregory.net/rapid v0.5.5 // indirect rsc.io/tmplfunc v0.0.3 // indirect - sigs.k8s.io/yaml v1.4.0 ) replace (