diff --git a/.changeset/brown-penguins-grin.md b/.changeset/brown-penguins-grin.md new file mode 100644 index 00000000000..24a06a030fc --- /dev/null +++ b/.changeset/brown-penguins-grin.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Fix in memory data source cache changes/bug that only allowed pipeline results where none of the data sources failed. #bugfix diff --git a/.changeset/chilled-bikes-unite.md b/.changeset/chilled-bikes-unite.md new file mode 100644 index 00000000000..e3e54852002 --- /dev/null +++ b/.changeset/chilled-bikes-unite.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal Add script to create test database user and update docs diff --git a/.changeset/flat-guests-marry.md b/.changeset/flat-guests-marry.md new file mode 100644 index 00000000000..c1eb6549a96 --- /dev/null +++ b/.changeset/flat-guests-marry.md @@ -0,0 +1,6 @@ +--- +"chainlink": minor +--- + +#internal Gas Estimator L1Oracles to be chain specific +#removed cmd/arbgas diff --git a/.changeset/four-shoes-trade.md b/.changeset/four-shoes-trade.md new file mode 100644 index 00000000000..cb5c9f4be6b --- /dev/null +++ b/.changeset/four-shoes-trade.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Removed AppConfig from Evm config #internal diff --git a/.changeset/fresh-lizards-love.md b/.changeset/fresh-lizards-love.md new file mode 100644 index 00000000000..8e6e5d5cfef --- /dev/null +++ b/.changeset/fresh-lizards-love.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal Updates required to work with chainlink-common changes to support grpc streams for capabilities diff --git a/.changeset/gold-bottles-tell.md b/.changeset/gold-bottles-tell.md new file mode 100644 index 00000000000..5289f368a55 --- /dev/null +++ b/.changeset/gold-bottles-tell.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#added : Re-enable abandoned transaction tracker diff --git a/.changeset/great-rockets-obey.md b/.changeset/great-rockets-obey.md new file mode 100644 index 00000000000..b90bc810a01 --- /dev/null +++ b/.changeset/great-rockets-obey.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#wip Keystone wrapper regenerate diff --git a/.changeset/hungry-ways-add.md b/.changeset/hungry-ways-add.md new file mode 100644 index 00000000000..657494de605 --- /dev/null +++ b/.changeset/hungry-ways-add.md @@ -0,0 +1,6 @@ +--- +"chainlink": patch +--- + +#bugfix +vrf fix replay number of blocks logic and add logging for job specs diff --git a/.changeset/kind-deers-leave.md b/.changeset/kind-deers-leave.md new file mode 100644 index 00000000000..ef88e78241c --- /dev/null +++ b/.changeset/kind-deers-leave.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +bump mockery in makefile #updated diff --git a/.changeset/loud-peaches-beg.md b/.changeset/loud-peaches-beg.md new file mode 100644 index 00000000000..cd880ae5f5c --- /dev/null +++ b/.changeset/loud-peaches-beg.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +support decimals #added diff --git a/.changeset/lucky-ghosts-give.md b/.changeset/lucky-ghosts-give.md new file mode 100644 index 00000000000..2ce47a6978b --- /dev/null +++ b/.changeset/lucky-ghosts-give.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +core/services/keystore: switch to sqlutil.DataStore #internal diff --git a/.changeset/lucky-windows-taste.md b/.changeset/lucky-windows-taste.md new file mode 100644 index 00000000000..bfcf559adb5 --- /dev/null +++ b/.changeset/lucky-windows-taste.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Validate support for postgresql-client 16, and update docker image's bundled postgresql-client from 15 to 16. #nops #updated diff --git a/.changeset/new-forks-grab.md b/.changeset/new-forks-grab.md new file mode 100644 index 00000000000..cb078beb29b --- /dev/null +++ b/.changeset/new-forks-grab.md @@ -0,0 +1,5 @@ +--- +"chainlink": removed +--- + +Drop unused queryTimeout config from TXM strategy #internal diff --git a/.changeset/orange-squids-kick.md b/.changeset/orange-squids-kick.md new file mode 100644 index 00000000000..a934e70063d --- /dev/null +++ b/.changeset/orange-squids-kick.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal Remote Trigger setup diff --git a/.changeset/plenty-wombats-grab.md b/.changeset/plenty-wombats-grab.md new file mode 100644 index 00000000000..84fb96f8b80 --- /dev/null +++ b/.changeset/plenty-wombats-grab.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#wip Regenerate Keystone wrappers diff --git a/.changeset/soft-hotels-decide.md b/.changeset/soft-hotels-decide.md new file mode 100644 index 00000000000..75b4cadd4e5 --- /dev/null +++ b/.changeset/soft-hotels-decide.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +switch more EVM components to use sqlutil.DataStore #internal diff --git a/.changeset/stale-terms-march.md b/.changeset/stale-terms-march.md new file mode 100644 index 00000000000..72ba417eac3 --- /dev/null +++ b/.changeset/stale-terms-march.md @@ -0,0 +1,7 @@ +--- +"chainlink": patch +--- + +Bump libocr => fd3cab206b2ca3b7ff207996b95673b2d6303ec4 + +#internal diff --git a/.changeset/weak-emus-reply.md b/.changeset/weak-emus-reply.md new file mode 100644 index 00000000000..ef0c1fe4dae --- /dev/null +++ b/.changeset/weak-emus-reply.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal Updated FindTxesWithAttemptsAndReceiptsByIdsAndState method signature to accept int64 for tx ID instead of big.Int diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 3542c865959..e52dd1aed7b 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -2,6 +2,9 @@ name: CI lint for Golang description: Runs CI lint for Golang inputs: # general inputs + id: + description: Unique metrics collection id + required: true name: description: Name of the lint action default: lint @@ -72,7 +75,7 @@ runs: if: always() uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: - id: chainlink-golang-ci + id: chainlink-golang-ci-${{ inputs.id }} basic-auth: ${{ inputs.gc-basic-auth }} hostname: ${{ inputs.gc-host }} org-id: ${{ inputs.gc-org-id }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 9eaf31d0ba2..5e9234eb491 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -63,6 +63,7 @@ jobs: uses: ./.github/actions/golangci-lint if: ${{ needs.filter.outputs.changes == 'true' }} with: + id: core gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} @@ -107,6 +108,9 @@ jobs: - name: Setup Go if: ${{ needs.filter.outputs.changes == 'true' }} uses: ./.github/actions/setup-go + - name: Run short tests + if: ${{ needs.filter.outputs.changes == 'true' }} + run: go test -short ./... - name: Setup Solana if: ${{ needs.filter.outputs.changes == 'true' }} uses: ./.github/actions/setup-solana diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml index 78c26ff258e..814c354cfe6 100644 --- a/.github/workflows/ci-scripts.yml +++ b/.github/workflows/ci-scripts.yml @@ -13,6 +13,7 @@ jobs: - name: Golang Lint uses: ./.github/actions/golangci-lint with: + id: scripts name: lint-scripts go-directory: core/scripts go-version-file: core/scripts/go.mod diff --git a/.github/workflows/helm-chart.yml b/.github/workflows/helm-chart.yml index 1a12a512e39..f0dd25c5dbb 100644 --- a/.github/workflows/helm-chart.yml +++ b/.github/workflows/helm-chart.yml @@ -9,24 +9,29 @@ on: jobs: ci-lint-helm-charts: runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - actions: read steps: - - name: Add repositories - run: | - helm repo add mockserver https://www.mock-server.com - helm repo add opentelemetry-collector https://open-telemetry.github.io/opentelemetry-helm-charts - helm repo add tempo https://grafana.github.io/helm-charts - helm repo add grafana https://grafana.github.io/helm-charts - name: ci-lint-helm-charts - uses: smartcontractkit/.github/actions/ci-lint-charts@6b08487b176ef7cad086526d0b54ddff6691c044 # ci-lint-charts@0.1.2 + uses: smartcontractkit/.github/actions/ci-lint-charts@7fa39741b11e66ed59f8aad786d4b9356c389f3f # ci-lint-charts@0.2.0 with: # chart testing inputs chart-testing-extra-args: "--lint-conf=lintconf.yaml" + charts-dir: charts/chainlink-cluster # grafana inputs metrics-job-name: ci-lint-helm-charts gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + + ci-kubeconform: + runs-on: ubuntu-latest + steps: + - name: ci-kubeconform + uses: smartcontractkit/.github/actions/ci-kubeconform@1ae8a9a984814c4daf50aa96f03be2cba0ef3fec # ci-kubeconform@0.2.0 + with: + # kubeform inputs + charts-dir: charts/chainlink-cluster + # grafana inputs + metrics-job-name: ci-kubeconform + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 1386bfef8f3..98d67a8b2d3 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -379,6 +379,7 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ inputs.evm-ref || github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: ${{ matrix.product.name }}-test-logs artifacts_location: | ./integration-tests/smoke/logs/ /tmp/gotest.log @@ -470,6 +471,7 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ inputs.evm-ref || github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: ${{ matrix.product.name }}-test-logs artifacts_location: | ./integration-tests/smoke/logs/ /tmp/gotest.log @@ -854,6 +856,7 @@ jobs: test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ steps.get_latest_version.outputs.latest_version }} + artifacts_name: node-migration-test-logs artifacts_location: | ./integration-tests/migration/logs /tmp/gotest.log @@ -865,14 +868,6 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Upload test log - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - if: failure() - with: - name: test-log-${{ matrix.product.name }} - path: /tmp/gotest.log - retention-days: 7 - continue-on-error: true - name: Collect Metrics if: always() id: collect-gha-metrics @@ -1160,21 +1155,17 @@ jobs: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ inputs.evm-ref || github.sha }} - artifacts_location: /home/runner/work/chainlink-solana/chainlink-solana/integration-tests/logs publish_check_name: Solana Smoke Test Results go_mod_path: ./integration-tests/go.mod cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: solana-test-logs + artifacts_location: | + ./integration-tests/smoke/logs + /tmp/gotest.log QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" run_setup: false - - name: Upload test log - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - if: failure() - with: - name: test-log-solana - path: /tmp/gotest.log - retention-days: 7 - continue-on-error: true + diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 860120972d5..f520e2307d9 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -15,6 +15,10 @@ on: - "Load" - "Stress" - "Spike" + test_list_regex: + description: "Regex for tests to run" + required: false + default: "(TestVRFV2Performance)" jobs: vrfv2_performance_test: name: VRFV2 Performance Test @@ -71,7 +75,7 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@5dd916d08c03cb5f9a97304f4f174820421bb946 # v2.3.11 with: - test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2Performance ./vrfv2 + test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run "${{ inputs.test_list_regex }}" ./vrfv2 test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ env.CHAINLINK_VERSION }} diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 463a7512b0c..16d37617a68 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -14,8 +14,11 @@ on: - "Soak" - "Load" - "Stress" - - "Spike" - + - "Spike" + test_list_regex: + description: "Regex for tests to run" + required: false + default: "(TestVRFV2PlusPerformance)" jobs: vrfv2plus_performance_test: name: VRFV2 Plus Performance Test @@ -72,7 +75,7 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@5dd916d08c03cb5f9a97304f4f174820421bb946 # v2.3.11 with: - test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance ./vrfv2plus + test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run "${{ inputs.test_list_regex }}" ./vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ env.CHAINLINK_VERSION }} diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index cea16f45f16..2d62ef864a5 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -79,7 +79,7 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge snapshot - if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) && needs.changes.outputs.changes == 'true' }} + if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) && !contains(fromJson('["keystone"]'), matrix.product) && needs.changes.outputs.changes == 'true' }} run: | forge snapshot --nmt "testFuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product }}.gas-snapshot id: snapshot diff --git a/.gitignore b/.gitignore index 7d07300311f..0a938ff9123 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,9 @@ tools/clroot/db.sqlite3-wal .DS_Store .envrc .env* +.dbenv !charts/chainlink-cluster/.env.example +!crib/.env.example !.github/actions/setup-postgres/.env .direnv .idea diff --git a/.goreleaser.devspace.yaml b/.goreleaser.devspace.yaml index 1c6b4768d98..bca65e90454 100644 --- a/.goreleaser.devspace.yaml +++ b/.goreleaser.devspace.yaml @@ -24,8 +24,8 @@ builds: post: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} {{ .Os }} {{ .Arch }} env: - CGO_ENABLED=1 - - CC=$ZIG_EXEC cc -target x86_64-linux-gnu - - CCX=$ZIG_EXEC c++ -target x86_64-linux-gnu + - CC=$ZIG_EXEC cc -target x86_64-linux-gnu -Wno-error=unused-command-line-argument + - CCX=$ZIG_EXEC c++ -target x86_64-linux-gnu -Wno-error=unused-command-line-argument flags: - -trimpath - -buildmode=pie diff --git a/CODEOWNERS b/CODEOWNERS index 65f0b58753f..8741cb7a685 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -75,7 +75,7 @@ core/scripts/gateway @smartcontractkit/functions /contracts/src/v0.8/l2ep @chris-de-leon-cll /contracts/src/v0.8/llo-feeds @smartcontractkit/mercury-team # TODO: mocks folder, folder should be removed and files moved to the correct folders -/contracts/src/v0.8/operatorforwarder @RensR +/contracts/src/v0.8/operatorforwarder @austinborn /contracts/src/v0.8/shared @RensR # TODO: tests folder, folder should be removed and files moved to the correct folders # TODO: transmission folder, owner should be found diff --git a/GNUmakefile b/GNUmakefile index 10d72cb724c..c5a0dfc6c21 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -104,6 +104,10 @@ testscripts: chainlink-test ## Install and run testscript against testdata/scrip testscripts-update: ## Update testdata/scripts/* files via testscript. make testscripts TS_FLAGS="-u" +.PHONY: setup-testdb +setup-testdb: ## Setup the test database. + ./core/scripts/setup_testdb.sh + .PHONY: testdb testdb: ## Prepares the test database. go run . local db preparetest @@ -125,7 +129,7 @@ gomods: ## Install gomods .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.38.0 + go install github.com/vektra/mockery/v2@v2.42.2 .PHONY: codecgen codecgen: $(codecgen) ## Install codecgen diff --git a/README.md b/README.md index 0d336dd22b3..447efb9cdea 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ regarding Chainlink social accounts, news, and networking. 2. Install [NodeJS v16](https://nodejs.org/en/download/package-manager/) & [pnpm via npm](https://pnpm.io/installation#using-npm). - It might be easier long term to use [nvm](https://nodejs.org/en/download/package-manager/#nvm) to switch between node versions for different projects. For example, assuming $NODE_VERSION was set to a valid version of NodeJS, you could run: `nvm install $NODE_VERSION && nvm use $NODE_VERSION` 3. Install [Postgres (>= 12.x)](https://wiki.postgresql.org/wiki/Detailed_installation_guides). It is recommended to run the latest major version of postgres. - - Note if you are running the official Chainlink docker image, the highest supported Postgres version is 15.x due to the bundled client. + - Note if you are running the official Chainlink docker image, the highest supported Postgres version is 16.x due to the bundled client. - You should [configure Postgres](https://www.postgresql.org/docs/current/ssl-tcp.html) to use SSL connection (or for testing you can set `?sslmode=disable` in your Postgres query string). 4. Ensure you have Python 3 installed (this is required by [solc-select](https://github.com/crytic/solc-select) which is needed to compile solidity contracts) 5. Download Chainlink: `git clone https://github.com/smartcontractkit/chainlink && cd chainlink` @@ -167,20 +167,28 @@ go generate ./... 5. Prepare your development environment: -```bash -export CL_DATABASE_URL=postgresql://127.0.0.1:5432/chainlink_test?sslmode=disable -``` +The tests require a postgres database. In turn, the environment variable +`CL_DATABASE_URL` must be set to value that can connect to `_test` database, and the user must be able to create and drop +the given `_test` database. Note: Other environment variables should not be set for all tests to pass -6. Drop/Create test database and run migrations: +There helper script for initial setup to create an appropriate test user. It requires postgres to be running on localhost at port 5432. You will be prompted for +the `postgres` user password +```bash +make setup-testdb ``` + +This script will save the `CL_DATABASE_URL` in `.dbenv` + +Changes to database require migrations to be run. Similarly, `pull`'ing the repo may require migrations to run. +After the one-time setup above: +``` +source .dbenv make testdb ``` -If you do end up modifying the migrations for the database, you will need to rerun - 7. Run tests: ```bash diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index a0a4b8a78cc..b76d55090dd 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -2,112 +2,9 @@ Example CL nodes cluster for system level tests -Install `kubefwd` (no nixpkg for it yet, planned) - -``` -brew install txn2/tap/kubefwd -``` - -If you want to build images you need [docker](https://docs.docker.com/engine/install/) service running - -Enter the shell (from the root project dir) - -``` -nix develop -``` - # Develop - -## New cluster - -We are using [devspace](https://www.devspace.sh/docs/getting-started/installation?x0=3) - -Configure the cluster, see `deployments.app.helm.values` and [values.yaml](./values.yaml) comments for more details - -Set up your K8s access - -``` -export DEVSPACE_IMAGE="..." -./setup.sh ${my-personal-namespace-name-crib} -``` - -Create a .env file based on the .env.sample file - -```sh -cp .env.sample .env -# Fill in the required values in .env -``` - -Build and deploy the current state of your repository - -``` -devspace deploy -``` - -Default `ttl` is `72h`, use `ttl` command to update if you need more time - -Valid values are `1h`, `2m`, `3s`, etc. Go time format is invalid `1h2m3s` - -``` -devspace run ttl ${namespace} 120h -``` - -If you want to deploy an image tag that is already available in ECR, use: - -``` -devspace deploy --override-image-tag "" -``` - -If you want to deploy an image tag from a public ECR repo, use: - -``` -export DEVSPACE_IMAGE=public.ecr.aws/chainlink/chainlink -devspace deploy --override-image-tag 2.9.0 -``` - -Forward ports to check UI or run tests - -``` -devspace run connect ${my-personal-namespace-name-crib} -``` - -List ingress hostnames - -``` -devspace run ingress-hosts -``` - -Destroy the cluster - -``` -devspace purge -``` - -## Running load tests - -Check this [doc](../../integration-tests/load/ocr/README.md) - -If you used `devspace dev ...` always use `devspace reset pods` to switch the pods back - -# Helm - -If you would like to use `helm` directly, please uncomment data in `values.yaml` - -## Install from local files - -``` -helm install -f values.yaml cl-cluster . -``` - -Forward all apps (in another terminal) - -``` -sudo kubefwd svc -n cl-cluster -``` - -Then you can connect and run your tests - ## Install from release +Note: The setup below doesn't work at the moment. Add the repository @@ -130,6 +27,7 @@ helm install -f values.yaml cl-cluster . ``` ## Create a new release +Note: The setup below doesn't work at the moment. Bump version in `Chart.yml` add your changes and add `helm_release` label to any PR to trigger a release @@ -143,52 +41,4 @@ helm test cl-cluster ``` helm uninstall cl-cluster -``` - -# Grafana dashboard - -We are using [Grabana](https://github.com/K-Phoen/grabana) lib to create dashboards programmatically - -You can also select dashboard platform in `INFRA_PLATFORM` either `kubernetes` or `docker` - -You can select the dashboard panels with `PANELS_INCLUDED` which is a list of panel names separated by comma -If you don't specify it will include core panels by default - -``` -export LOKI_TENANT_ID=promtail -export LOKI_URL=... -export GRAFANA_URL=... -export GRAFANA_TOKEN=... -export PROMETHEUS_DATA_SOURCE_NAME=Thanos -export LOKI_DATA_SOURCE_NAME=Loki -export INFRA_PLATFORM=kubernetes -export GRAFANA_FOLDER=DashboardCoreDebug -export DASHBOARD_NAME=CL-Cluster - -devspace run dashboard_deploy -``` - -Open Grafana folder `DashboardCoreDebug` and find dashboard `ChainlinkClusterDebug` - -# Testing - -Deploy your dashboard and run soak/load [tests](../../integration-tests/load/), check [README](../../integration-tests/README.md) for further explanations - -``` -devspace run dashboard_deploy -devspace run workload -devspace run dashboard_test -``` - -# Local Testing - -Go to [dashboard-lib](../../dashboard) and link the modules locally - -``` -cd dashboard -pnpm link --global -cd charts/chainlink-cluster/dashboard/tests -pnpm link --global dashboard-tests -``` - -Then run the tests with commands mentioned above +``` \ No newline at end of file diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index e68a047e078..9a66e164aa0 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index dfe9f32664a..ec83158a5ff 100644 --- a/common/client/mock_node_client_test.go +++ b/common/client/mock_node_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_node_selector_test.go b/common/client/mock_node_selector_test.go index bd0805fa4e6..996d064daa4 100644 --- a/common/client/mock_node_selector_test.go +++ b/common/client/mock_node_selector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go index 56132b2cee8..ee2cacb9274 100644 --- a/common/client/mock_node_test.go +++ b/common/client/mock_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index 731d0f94cf2..54f57e81f65 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_send_only_client_test.go b/common/client/mock_send_only_client_test.go index b667a2ceb59..b07e10ed8ce 100644 --- a/common/client/mock_send_only_client_test.go +++ b/common/client/mock_send_only_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/client/mock_send_only_node_test.go b/common/client/mock_send_only_node_test.go index 0a319db5f78..4822c2620b8 100644 --- a/common/client/mock_send_only_node_test.go +++ b/common/client/mock_send_only_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package client diff --git a/common/headtracker/mocks/head_trackable.go b/common/headtracker/mocks/head_trackable.go index 22bc5cb280a..417152d8cbd 100644 --- a/common/headtracker/mocks/head_trackable.go +++ b/common/headtracker/mocks/head_trackable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/headtracker/mocks/head_tracker.go b/common/headtracker/mocks/head_tracker.go index 9261ef3221b..2321c3bfdca 100644 --- a/common/headtracker/mocks/head_tracker.go +++ b/common/headtracker/mocks/head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index a13673bf91b..1651f6417bf 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -689,7 +689,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save // is relatively benign and probably nobody will ever run into it in // practice, but something to be aware of. if etx.PipelineTaskRunID.Valid && eb.resumeCallback != nil && etx.SignalCallback { - err := eb.resumeCallback(etx.PipelineTaskRunID.UUID, nil, fmt.Errorf("fatal error while sending transaction: %s", etx.Error.String)) + err := eb.resumeCallback(ctx, etx.PipelineTaskRunID.UUID, nil, fmt.Errorf("fatal error while sending transaction: %s", etx.Error.String)) if errors.Is(err, sql.ErrNoRows) { lgr.Debugw("callback missing or already resumed", "etxID", etx.ID) } else if err != nil { diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index 53e1c3c4206..d61f9a3dddd 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -1120,7 +1120,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Res } ec.lggr.Debugw("Callback: resuming tx with receipt", "output", output, "taskErr", taskErr, "pipelineTaskRunID", data.ID) - if err := ec.resumeCallback(data.ID, output, taskErr); err != nil { + if err := ec.resumeCallback(ctx, data.ID, output, taskErr); err != nil { return fmt.Errorf("failed to resume suspended pipeline run: %w", err) } // Mark tx as having completed callback diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 37b0822941d..935e7313817 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -184,7 +184,7 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx } // FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, ids, states, chainID) if len(ret) == 0 { @@ -193,10 +193,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { return rf(ctx, ids, states, chainID) } - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { r0 = rf(ctx, ids, states, chainID) } else { if ret.Get(0) != nil { @@ -204,7 +204,7 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx } } - if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) error); ok { r1 = rf(ctx, ids, states, chainID) } else { r1 = ret.Error(1) diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 8c2dd6b827e..b752ec63f13 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -140,9 +140,6 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) resendUnco return fmt.Errorf("Resender failed getting enabled keys for chain %s: %w", er.chainID.String(), err) } - // Tracker currently disabled for BCI-2638; refactor required - // resendAddresses = append(resendAddresses, er.tracker.GetAbandonedAddresses()...) - ageThreshold := er.txConfig.ResendAfterThreshold() maxInFlightTransactions := er.txConfig.MaxInFlight() olderThan := time.Now().Add(-ageThreshold) diff --git a/common/txmgr/strategies.go b/common/txmgr/strategies.go index 3772e6d1d20..6e037658854 100644 --- a/common/txmgr/strategies.go +++ b/common/txmgr/strategies.go @@ -3,7 +3,6 @@ package txmgr import ( "context" "fmt" - "time" "github.com/google/uuid" @@ -14,9 +13,9 @@ var _ txmgrtypes.TxStrategy = SendEveryStrategy{} // NewQueueingTxStrategy creates a new TxStrategy that drops the oldest transactions after the // queue size is exceeded if a queue size is specified, and otherwise does not drop transactions. -func NewQueueingTxStrategy(subject uuid.UUID, queueSize uint32, queryTimeout time.Duration) (strategy txmgrtypes.TxStrategy) { +func NewQueueingTxStrategy(subject uuid.UUID, queueSize uint32) (strategy txmgrtypes.TxStrategy) { if queueSize > 0 { - strategy = NewDropOldestStrategy(subject, queueSize, queryTimeout) + strategy = NewDropOldestStrategy(subject, queueSize) } else { strategy = SendEveryStrategy{} } @@ -41,15 +40,14 @@ var _ txmgrtypes.TxStrategy = DropOldestStrategy{} // DropOldestStrategy will send the newest N transactions, older ones will be // removed from the queue type DropOldestStrategy struct { - subject uuid.UUID - queueSize uint32 - queryTimeout time.Duration + subject uuid.UUID + queueSize uint32 } // NewDropOldestStrategy creates a new TxStrategy that drops the oldest transactions after the // queue size is exceeded. -func NewDropOldestStrategy(subject uuid.UUID, queueSize uint32, queryTimeout time.Duration) DropOldestStrategy { - return DropOldestStrategy{subject, queueSize, queryTimeout} +func NewDropOldestStrategy(subject uuid.UUID, queueSize uint32) DropOldestStrategy { + return DropOldestStrategy{subject, queueSize} } func (s DropOldestStrategy) Subject() uuid.NullUUID { @@ -57,10 +55,6 @@ func (s DropOldestStrategy) Subject() uuid.NullUUID { } func (s DropOldestStrategy) PruneQueue(ctx context.Context, pruneService txmgrtypes.UnstartedTxQueuePruner) (ids []int64, err error) { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, s.queryTimeout) - defer cancel() - // NOTE: We prune one less than the queue size to prevent the queue from exceeding the max queue size. Which could occur if a new transaction is added to the queue right after we prune. ids, err = pruneService.PruneUnstartedTxQueue(ctx, s.queueSize-1, s.subject) if err != nil { diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go index c63d9c264fc..a7236472710 100644 --- a/common/txmgr/tracker.go +++ b/common/txmgr/tracker.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" @@ -22,17 +23,10 @@ const ( // handleTxesTimeout represents a sanity limit on how long handleTxesByState // should take to complete handleTxesTimeout = 10 * time.Minute + // batchSize is the number of txes to fetch from the txStore at once + batchSize = 1000 ) -// AbandonedTx is a transaction who's 'FromAddress' was removed from the KeyStore(by the Node Operator). -// Thus, any new attempts for this Tx can't be signed/created. This means no fee bumping can be done. -// However, the Tx may still have live attempts in the chain's mempool, and could get confirmed on the -// chain as-is. Thus, the TXM should not directly discard this Tx. -type AbandonedTx[ADDR types.Hashable] struct { - id int64 - fromAddress ADDR -} - // Tracker tracks all transactions which have abandoned fromAddresses. // The fromAddresses can be deleted by Node Operators from the KeyStore. In such cases, // existing in-flight transactions for these fromAddresses are considered abandoned too. @@ -48,19 +42,22 @@ type Tracker[ FEE feetypes.Fee, ] struct { services.StateMachine - txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] - keyStore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] - chainID CHAIN_ID - lggr logger.Logger - enabledAddrs map[ADDR]bool - txCache map[int64]AbandonedTx[ADDR] - ttl time.Duration + txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] + keyStore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] + chainID CHAIN_ID + lggr logger.Logger + lock sync.Mutex - mb *mailbox.Mailbox[int64] - wg sync.WaitGroup - isStarted bool - ctx context.Context - ctxCancel context.CancelFunc + enabledAddrs map[ADDR]bool + txCache map[int64]ADDR // cache tx fromAddress by txID + + ttl time.Duration + mb *mailbox.Mailbox[int64] + + initSync sync.Mutex + wg sync.WaitGroup + chStop services.StopChan + isStarted bool } func NewTracker[ @@ -83,7 +80,7 @@ func NewTracker[ chainID: chainID, lggr: logger.Named(lggr, "TxMgrTracker"), enabledAddrs: map[ADDR]bool{}, - txCache: map[int64]AbandonedTx[ADDR]{}, + txCache: map[int64]ADDR{}, ttl: defaultTTL, mb: mailbox.NewSingle[int64](), lock: sync.Mutex{}, @@ -99,75 +96,84 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx c } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal(ctx context.Context) (err error) { - tr.lock.Lock() - defer tr.lock.Unlock() - - tr.ctx, tr.ctxCancel = context.WithCancel(context.Background()) + tr.initSync.Lock() + defer tr.initSync.Unlock() if err := tr.setEnabledAddresses(ctx); err != nil { return fmt.Errorf("failed to set enabled addresses: %w", err) } - tr.lggr.Info("Enabled addresses set") + tr.lggr.Infof("enabled addresses set for chainID %v", tr.chainID) - if err := tr.trackAbandonedTxes(ctx); err != nil { - return fmt.Errorf("failed to track abandoned txes: %w", err) - } - - tr.isStarted = true - if len(tr.txCache) == 0 { - tr.lggr.Info("no abandoned txes found, skipping runLoop") - return nil - } - - tr.lggr.Infof("%d abandoned txes found, starting runLoop", len(tr.txCache)) + tr.chStop = make(chan struct{}) tr.wg.Add(1) - go tr.runLoop() + go tr.runLoop(tr.chStop.NewCtx()) + tr.isStarted = true return nil } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() error { - tr.lock.Lock() - defer tr.lock.Unlock() return tr.StopOnce("Tracker", func() error { return tr.closeInternal() }) } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) closeInternal() error { + tr.initSync.Lock() + defer tr.initSync.Unlock() + tr.lggr.Info("stopping tracker") if !tr.isStarted { - return fmt.Errorf("tracker not started") + return fmt.Errorf("tracker is not started: %w", services.ErrAlreadyStopped) } - tr.ctxCancel() + + close(tr.chStop) tr.wg.Wait() tr.isStarted = false return nil } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop(ctx context.Context, cancel context.CancelFunc) { defer tr.wg.Done() + defer cancel() + + if err := tr.trackAbandonedTxes(ctx); err != nil { + tr.lggr.Errorf("failed to track abandoned txes: %v", err) + return + } + if err := tr.handleTxesByState(ctx); err != nil { + tr.lggr.Errorf("failed to handle txes by state: %v", err) + return + } + if tr.AbandonedTxCount() == 0 { + tr.lggr.Info("no abandoned txes found, skipping runLoop") + return + } + tr.lggr.Infof("%d abandoned txes found, starting runLoop", tr.AbandonedTxCount()) + ttlExceeded := time.NewTicker(tr.ttl) defer ttlExceeded.Stop() for { select { case <-tr.mb.Notify(): for { - if tr.ctx.Err() != nil { - return - } - blockHeight, exists := tr.mb.Retrieve() - if !exists { + blockHeight := tr.mb.RetrieveLatestAndClear() + if blockHeight == 0 { break } - if err := tr.HandleTxesByState(tr.ctx, blockHeight); err != nil { - tr.lggr.Errorw(fmt.Errorf("failed to handle txes by state: %w", err).Error()) + if err := tr.handleTxesByState(ctx); err != nil { + tr.lggr.Errorf("failed to handle txes by state: %v", err) + return + } + if tr.AbandonedTxCount() == 0 { + tr.lggr.Info("all abandoned txes handled, stopping runLoop") + return } } case <-ttlExceeded.C: tr.lggr.Info("ttl exceeded") - tr.MarkAllTxesFatal(tr.ctx) + tr.markAllTxesFatal(ctx) return - case <-tr.ctx.Done(): + case <-ctx.Done(): return } } @@ -177,24 +183,31 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetAbandone tr.lock.Lock() defer tr.lock.Unlock() - if !tr.isStarted { - return []ADDR{} - } - abandonedAddrs := make([]ADDR, len(tr.txCache)) - for _, atx := range tr.txCache { - abandonedAddrs = append(abandonedAddrs, atx.fromAddress) + for _, fromAddress := range tr.txCache { + abandonedAddrs = append(abandonedAddrs, fromAddress) } return abandonedAddrs } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsStarted() bool { +// AbandonedTxCount returns the number of abandoned txes currently being tracked +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) AbandonedTxCount() int { tr.lock.Lock() defer tr.lock.Unlock() + return len(tr.txCache) +} + +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsStarted() bool { + tr.initSync.Lock() + defer tr.initSync.Unlock() return tr.isStarted } +// setEnabledAddresses is called on startup to set the enabled addresses for the chain func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) setEnabledAddresses(ctx context.Context) error { + tr.lock.Lock() + defer tr.lock.Unlock() + enabledAddrs, err := tr.keyStore.EnabledAddressesForChain(ctx, tr.chainID) if err != nil { return fmt.Errorf("failed to get enabled addresses for chain: %w", err) @@ -210,54 +223,58 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) setEnabledA return nil } -// trackAbandonedTxes called once to find and insert all abandoned txes into the tracker. +// trackAbandonedTxes called on startup to find and insert all abandoned txes into the tracker. func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) trackAbandonedTxes(ctx context.Context) (err error) { - if tr.isStarted { - return fmt.Errorf("tracker already started") - } - - tr.lggr.Info("Retrieving non fatal transactions from txStore") - nonFatalTxes, err := tr.txStore.GetNonFatalTransactions(ctx, tr.chainID) - if err != nil { - return fmt.Errorf("failed to get non fatal txes from txStore: %w", err) - } - - // insert abandoned txes - for _, tx := range nonFatalTxes { - if !tr.enabledAddrs[tx.FromAddress] { - tr.insertTx(tx) + return sqlutil.Batch(func(offset, limit uint) (count uint, err error) { + var enabledAddrs []ADDR + for addr := range tr.enabledAddrs { + enabledAddrs = append(enabledAddrs, addr) } - } - if err := tr.handleTxesByState(ctx, 0); err != nil { - return fmt.Errorf("failed to handle txes by state: %w", err) - } - - return nil + nonFatalTxes, err := tr.txStore.GetAbandonedTransactionsByBatch(ctx, tr.chainID, enabledAddrs, offset, limit) + if err != nil { + return 0, fmt.Errorf("failed to get non fatal txes from txStore: %w", err) + } + // insert abandoned txes + tr.lock.Lock() + for _, tx := range nonFatalTxes { + if !tr.enabledAddrs[tx.FromAddress] { + tr.txCache[tx.ID] = tx.FromAddress + tr.lggr.Debugf("inserted tx %v", tx.ID) + } + } + tr.lock.Unlock() + return uint(len(nonFatalTxes)), nil + }, batchSize) } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HandleTxesByState(ctx context.Context, blockHeight int64) error { +// handleTxesByState handles all txes in the txCache by their state +// It's called on every new blockHeight and also on startup to handle all txes in the txCache +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleTxesByState(ctx context.Context) error { tr.lock.Lock() defer tr.lock.Unlock() - tr.ctx, tr.ctxCancel = context.WithTimeout(ctx, handleTxesTimeout) - defer tr.ctxCancel() - return tr.handleTxesByState(ctx, blockHeight) -} + ctx, cancel := context.WithTimeout(ctx, handleTxesTimeout) + defer cancel() -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleTxesByState(ctx context.Context, blockHeight int64) error { - tr.lggr.Info("Handling transactions by state") + for id := range tr.txCache { + if ctx.Err() != nil { + return ctx.Err() + } - for id, atx := range tr.txCache { - tx, err := tr.txStore.GetTxByID(ctx, atx.id) + tx, err := tr.txStore.GetTxByID(ctx, id) if err != nil { - return fmt.Errorf("failed to get tx by ID: %w", err) + tr.lggr.Errorf("failed to get tx by ID: %v", err) + continue + } + if tx == nil { + tr.lggr.Warnf("tx with ID %v no longer exists, removing from tracker", id) + delete(tr.txCache, id) + continue } switch tx.State { case TxConfirmed: - if err := tr.handleConfirmedTx(tx, blockHeight); err != nil { - return fmt.Errorf("failed to handle confirmed txes: %w", err) - } + // TODO: Handle finalized state https://smartcontract-it.atlassian.net/browse/BCI-2920 case TxConfirmedMissingReceipt, TxUnconfirmed: // Keep tracking tx case TxInProgress, TxUnstarted: @@ -266,50 +283,20 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleTxesB // is deleted, we can't sign it. errMsg := "The FromAddress for this Tx was deleted before this Tx could be broadcast to the chain." if err := tr.markTxFatal(ctx, tx, errMsg); err != nil { - return fmt.Errorf("failed to mark tx as fatal: %w", err) + tr.lggr.Errorf("failed to mark tx as fatal: %v", err) + continue } delete(tr.txCache, id) case TxFatalError: delete(tr.txCache, id) default: - tr.lggr.Errorw(fmt.Sprintf("unhandled transaction state: %v", tx.State)) + tr.lggr.Errorf("unhandled transaction state: %v", tx.State) } } return nil } -// handleConfirmedTx removes a transaction from the tracker if it's been finalized on chain -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleConfirmedTx( - tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - blockHeight int64, -) error { - finalized, err := tr.txStore.IsTxFinalized(tr.ctx, blockHeight, tx.ID, tr.chainID) - if err != nil { - return fmt.Errorf("failed to check if tx is finalized: %w", err) - } - - if finalized { - delete(tr.txCache, tx.ID) - } - - return nil -} - -// insertTx inserts a transaction into the tracker as an AbandonedTx -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) insertTx( - tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) { - if _, contains := tr.txCache[tx.ID]; contains { - return - } - - tr.txCache[tx.ID] = AbandonedTx[ADDR]{ - id: tx.ID, - fromAddress: tx.FromAddress, - } - tr.lggr.Debugw(fmt.Sprintf("inserted tx %v", tx.ID)) -} - func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markTxFatal(ctx context.Context, tx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], errMsg string) error { @@ -323,22 +310,26 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markTxFatal return nil } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllTxesFatal(ctx context.Context) { +// markAllTxesFatal tries to mark all txes in the txCache as fatal and removes them from the cache +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markAllTxesFatal(ctx context.Context) { tr.lock.Lock() defer tr.lock.Unlock() + errMsg := fmt.Sprintf( - "fromAddress for this Tx was deleted, and existing attempts onchain didn't finalize within %d hours, thus this Tx was abandoned.", + "tx abandoned: fromAddress for this tx was deleted and existing attempts didn't finalize onchain within %d hours", int(tr.ttl.Hours())) - for _, atx := range tr.txCache { - tx, err := tr.txStore.GetTxByID(ctx, atx.id) + for id := range tr.txCache { + tx, err := tr.txStore.GetTxByID(ctx, id) if err != nil { - tr.lggr.Errorw(fmt.Errorf("failed to get tx by ID: %w", err).Error()) + tr.lggr.Errorf("failed to get tx by ID: %v", err) + delete(tr.txCache, id) continue } if err := tr.markTxFatal(ctx, tx, errMsg); err != nil { - tr.lggr.Errorw(fmt.Errorf("failed to mark tx as abandoned: %w", err).Error()) + tr.lggr.Errorf("failed to mark tx as abandoned: %v", err) } + delete(tr.txCache, id) } } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index d183a8c3ade..4d4eabe5c40 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -27,7 +27,7 @@ import ( // https://www.notion.so/chainlink/Txm-Architecture-Overview-9dc62450cd7a443ba9e7dceffa1a8d6b // ResumeCallback is assumed to be idempotent -type ResumeCallback func(id uuid.UUID, result interface{}, err error) error +type ResumeCallback func(ctx context.Context, id uuid.UUID, result interface{}, err error) error // TxManager is the main component of the transaction manager. // It is also the interface to external callers. @@ -57,7 +57,7 @@ type TxManager[ // Find transactions with a non-null TxMeta field that was provided and a receipt block number greater than or equal to the one provided FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) // Find transactions loaded with transaction attempts and receipts by transaction IDs and states - FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (nullv4.Time, error) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (nullv4.Int, error) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) @@ -190,12 +190,9 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx return fmt.Errorf("Txm: Estimator failed to start: %w", err) } - /* Tracker currently disabled for BCI-2638; refactor required - b.logger.Info("Txm starting tracker") if err := ms.Start(ctx, b.tracker); err != nil { return fmt.Errorf("Txm: Tracker failed to start: %w", err) } - */ b.logger.Info("Txm starting runLoop") b.wg.Add(1) @@ -275,12 +272,6 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (m merr = errors.Join(merr, fmt.Errorf("Txm: failed to close TxAttemptBuilder: %w", err)) } - /* Tracker currently disabled for BCI-2638; refactor required - if err := b.tracker.Close(); err != nil { - merr = errors.Join(merr, fmt.Errorf("Txm: failed to close Tracker: %w", err)) - } - */ - return nil }) } @@ -329,6 +320,9 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() if err := b.broadcaster.closeInternal(); err != nil { b.logger.Panicw(fmt.Sprintf("Failed to Close Broadcaster: %v", err), "err", err) } + if err := b.tracker.closeInternal(); err != nil { + b.logger.Panicw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) + } if err := b.confirmer.closeInternal(); err != nil { b.logger.Panicw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) } @@ -337,16 +331,17 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() close(r.done) } var wg sync.WaitGroup - // two goroutines to handle independent backoff retries starting: + // three goroutines to handle independent backoff retries starting: // - Broadcaster // - Confirmer + // - Tracker // If chStop is closed, we mark stopped=true so that the main runloop // can check and exit early if necessary // // execReset will not return until either: - // 1. Both Broadcaster and Confirmer started successfully + // 1. Broadcaster, Confirmer, and Tracker all started successfully // 2. chStop was closed (txmgr exit) - wg.Add(2) + wg.Add(3) go func() { defer wg.Done() // Retry indefinitely on failure @@ -366,6 +361,25 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() } } }() + go func() { + defer wg.Done() + // Retry indefinitely on failure + backoff := iutils.NewRedialBackoff() + for { + select { + case <-time.After(backoff.Duration()): + if err := b.tracker.startInternal(ctx); err != nil { + b.logger.Criticalw("Failed to start Tracker", "err", err) + b.SvcErrBuffer.Append(err) + continue + } + return + case <-b.chStop: + stopOnce.Do(func() { stopped = true }) + return + } + } + }() go func() { defer wg.Done() // Retry indefinitely on failure @@ -395,8 +409,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() b.broadcaster.Trigger(address) case head := <-b.chHeads: b.confirmer.mb.Deliver(head) - // Tracker currently disabled for BCI-2638; refactor required - // b.tracker.mb.Deliver(head.BlockNumber()) + b.tracker.mb.Deliver(head.BlockNumber()) case reset := <-b.reset: // This check prevents the weird edge-case where you can select // into this block after chStop has already been closed and the @@ -424,12 +437,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { b.logger.Errorw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) } - /* Tracker currently disabled for BCI-2638; refactor required err = b.tracker.Close() if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { b.logger.Errorw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) } - */ return case <-keysChanged: // This check prevents the weird edge-case where you can select @@ -587,7 +598,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWi return } -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { txes, err = b.txStore.FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx, ids, states, chainID) return } @@ -667,7 +678,7 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Fin func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return txes, errors.New(n.ErrMsg) } -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return txes, errors.New(n.ErrMsg) } diff --git a/common/txmgr/types/mocks/forwarder_manager.go b/common/txmgr/types/mocks/forwarder_manager.go index bf61d0c3d27..fe40e7bb5e2 100644 --- a/common/txmgr/types/mocks/forwarder_manager.go +++ b/common/txmgr/types/mocks/forwarder_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index 7e825322977..f6f572a35ff 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go index 041214b80c6..716b3e5175a 100644 --- a/common/txmgr/types/mocks/reaper_chain_config.go +++ b/common/txmgr/types/mocks/reaper_chain_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index 20ecbde0945..8171b29bbed 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 814207d3986..be2c0aef723 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -551,7 +551,7 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPen } // FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, ids, states, chainID) if len(ret) == 0 { @@ -560,10 +560,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { return rf(ctx, ids, states, chainID) } - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { r0 = rf(ctx, ids, states, chainID) } else { if ret.Get(0) != nil { @@ -571,7 +571,7 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit } } - if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []txmgrtypes.TxState, *big.Int) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, []int64, []txmgrtypes.TxState, *big.Int) error); ok { r1 = rf(ctx, ids, states, chainID) } else { r1 = ret.Error(1) @@ -700,29 +700,29 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ return r0, r1 } -// GetInProgressTxAttempts provides a mock function with given fields: ctx, address, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(ctx, address, chainID) +// GetAbandonedTransactionsByBatch provides a mock function with given fields: ctx, chainID, enabledAddrs, offset, limit +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetAbandonedTransactionsByBatch(ctx context.Context, chainID CHAIN_ID, enabledAddrs []ADDR, offset uint, limit uint) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, chainID, enabledAddrs, offset, limit) if len(ret) == 0 { - panic("no return value specified for GetInProgressTxAttempts") + panic("no return value specified for GetAbandonedTransactionsByBatch") } - var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(ctx, address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, []ADDR, uint, uint) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, chainID, enabledAddrs, offset, limit) } - if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(ctx, address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, []ADDR, uint, uint) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, chainID, enabledAddrs, offset, limit) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { - r1 = rf(ctx, address, chainID) + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID, []ADDR, uint, uint) error); ok { + r1 = rf(ctx, chainID, enabledAddrs, offset, limit) } else { r1 = ret.Error(1) } @@ -730,29 +730,29 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgre return r0, r1 } -// GetNonFatalTransactions provides a mock function with given fields: ctx, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(ctx, chainID) +// GetInProgressTxAttempts provides a mock function with given fields: ctx, address, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { - panic("no return value specified for GetNonFatalTransactions") + panic("no return value specified for GetInProgressTxAttempts") } - var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] + var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(ctx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, address, chainID) } - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(ctx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, address, chainID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) + r0 = ret.Get(0).([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { - r1 = rf(ctx, chainID) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, address, chainID) } else { r1 = ret.Error(1) } diff --git a/common/txmgr/types/mocks/tx_strategy.go b/common/txmgr/types/mocks/tx_strategy.go index 92d4b7da569..414fdb44cb0 100644 --- a/common/txmgr/types/mocks/tx_strategy.go +++ b/common/txmgr/types/mocks/tx_strategy.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index f061f0ea628..bca2d1e3647 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -52,7 +52,7 @@ type TxStore[ // Find transactions with a non-null TxMeta field that was provided and a receipt block number greater than or equal to the one provided FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) // Find transactions loaded with transaction attempts and receipts by transaction IDs and states - FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []TxState, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []TxState, chainID *big.Int) (tx []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) } // TransactionStore contains the persistence layer methods needed to manage Txs and TxAttempts @@ -85,7 +85,7 @@ type TransactionStore[ FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error) GetTxInProgress(ctx context.Context, fromAddress ADDR) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - GetNonFatalTransactions(ctx context.Context, chainID CHAIN_ID) (txs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + GetAbandonedTransactionsByBatch(ctx context.Context, chainID CHAIN_ID, enabledAddrs []ADDR, offset, limit uint) (txs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetTxByID(ctx context.Context, id int64) (tx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (exists bool, err error) LoadTxAttempts(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index fd5c95d472f..a8cbca07355 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/contracts/.changeset/heavy-horses-greet.md b/contracts/.changeset/heavy-horses-greet.md new file mode 100644 index 00000000000..51912232c26 --- /dev/null +++ b/contracts/.changeset/heavy-horses-greet.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +support decimals #added diff --git a/contracts/.changeset/mean-items-talk.md b/contracts/.changeset/mean-items-talk.md new file mode 100644 index 00000000000..e03d49335ad --- /dev/null +++ b/contracts/.changeset/mean-items-talk.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +#wip Keystone custom error diff --git a/contracts/.changeset/old-pianos-trade.md b/contracts/.changeset/old-pianos-trade.md new file mode 100644 index 00000000000..10c0097bded --- /dev/null +++ b/contracts/.changeset/old-pianos-trade.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +#wip Add Capability Registry skeleton diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md index 212cd979e39..b9294de5765 100644 --- a/contracts/STYLE_GUIDE.md +++ b/contracts/STYLE_GUIDE.md @@ -6,11 +6,11 @@ Rules are all enforced through CI, this can be through Solhint rules or other to ## Background -Our starting point is the [official Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.21/style-guide.html) and [ConsenSys's Secure Development practices](https://consensys.github.io/smart-contract-best-practices/), but we deviate in some ways. We lean heavily on [Prettier](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc) for formatting, and if you have to set up a new Solidity project we recommend starting with [our prettier config](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc). We are trying to automate as much of this styleguide with Solhint as possible. +Our starting point is the [official Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.21/style-guide.html) and [ConsenSys's Secure Development practices](https://consensys.github.io/smart-contract-best-practices/), but we deviate in some ways. We lean heavily on [Prettier](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc) for formatting, and if you have to set up a new Solidity project we recommend starting with [our prettier config](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/.prettierrc). We are trying to automate as much of this style guide with Solhint as possible. -This guide is not meant to be applied retroactively. There is no need to rewrite existing code to adhere to this guide, and when making (small) changes in existing files, it is not required to do so in accordance to this guide if it would conflict with other practices in that existing file. Consistency is preferred. +This guide is not meant to be applied retroactively. There is no need to rewrite existing code to adhere to this guide, and when making (small) changes in existing files, it is not required to adhere to this guide if it conflicts with other practices in that existing file. Consistency is preferred. -We will be looking into `forge fmt`, but for now we still use `prettier`. +We will be looking into `forge fmt`, but for now, we still use `prettier`. # Guidelines @@ -22,17 +22,17 @@ We will be looking into `forge fmt`, but for now we still use `prettier`. ### Delineate Unaudited Code -- In a large repo it is worthwhile to keep code that has not yet been audited separate from the code that has been audited. This allows you to easily keep track of which files need to be reviewed. - - E.g. we keep unaudited code in a directory named `dev` that exists within each projects folder. Only once it has been audited we move the audited files out of `dev` and only then is it considered safe to deploy. +- In a large repo, it is worthwhile to keep code that has not yet been audited separately from the code that has been audited. This allows you to easily keep track of which files need to be reviewed. + - E.g. we keep unaudited code in a directory named `dev` that exists within each project's folder. Only once it has been audited we move the audited files out of `dev` and only then is it considered safe to deploy. - This `dev` folder also has implications for when code is valid for bug bounties, so be extra careful to move functionality out of a `dev` folder. -## comments -- Besides comment above functions/structs, comments should live everywhere a reader might be confused. +## Comments +- Besides comments above functions and structs, comments should live everywhere a reader might be confused. Don’t overestimate the reader of your contract, expect confusion in many places and document accordingly. This will help massively during audits and onboarding new team members. -- Headers should be used to group functionality, the following header style and length is recommended. - - Don’t use headers for a single function, or to say “getters”. Group by functionality e.g. the `Tokens and pools` , or `fees` logic within the CCIP OnRamp. +- Headers should be used to group functionality, the following header style and length are recommended. + - Don’t use headers for a single function, or to say “getters”. Group by functionality e.g. the `Tokens and pools`, or `fees` logic within the CCIP OnRamp. ```solidity // ================================================================ @@ -48,7 +48,7 @@ We will be looking into `forge fmt`, but for now we still use `prettier`. ## Variables -- Function arguments are named like this: `argumentName`. No leading or trailing underscores necessary. +- Function arguments are named like this: `argumentName`. No leading or trailing underscores are necessary. - Names should be explicit on the unit it contains, e.g. a network fee that is charged in USD cents ```solidity @@ -64,11 +64,11 @@ uint256 networkFeeUSDCents; // good ### Structs -- Structs should contain struct packing comments to clearly indicate the storage slot layout +- Structs should contain struct packing comments to indicate the storage slot layout - Using the exact characters from the example below will ensure visually appealing struct packing comments. - Notice there is no line on the unpacked last `fee` item. - Struct should contain comments, clearly indicating the denomination of values e.g. 0.01 USD if the variable name doesn’t already do that (which it should). - - Simple tool that could help packing structs and adding comments: https://github.com/RensR/Spack + - A simple tool that could help with packing structs and adding comments: https://github.com/RensR/Spack ```solidity /// @dev Struct to hold the fee configuration for a fee token, same as the FeeTokenConfig but with @@ -98,13 +98,13 @@ struct FeeTokenConfigArgs { ### Return Values - If an address is cast as a contract type, return the type, do not cast back to the address type. - This prevents the consumer of the method signature from having to cast again, but presents an equivalent API for off-chain APIs. + This prevents the consumer of the method signature from having to cast again but presents an equivalent API for off-chain APIs. Additionally, it is a more declarative API, providing more context if we return a type. ## Modifiers - Only extract a modifier once a check is duplicated in multiple places. Modifiers arguably hurt readability, so we have found that they are not worth extracting until there is duplication. -- Modifiers should be treated as if they are view functions. They should not change state, only read it. While it is possible to change state in a modifier, it is unconventional and surprising. +- Modifiers should be treated as if they are view functions. They should not change state, only read it. While it is possible to change the state in a modifier, it is unconventional and surprising. - Modifiers tend to bloat contract size because the code is duplicated wherever the modifier is used. ## Events @@ -146,7 +146,7 @@ assembly { return (success, retData); ``` -This will cost slightly more gas to copy the response into memory, but will ultimately make contract usage more understandable and easier to debug. Whether it is worth the extra gas is a judgement call you’ll have to make based on your needs. +This will cost slightly more gas to copy the response into memory, but will ultimately make contract usage more understandable and easier to debug. Whether it is worth the extra gas is a judgment call you’ll have to make based on your needs. The original error will not be human-readable in an off-chain explorer because it is RLP hex encoded but is easily decoded with standard Solidity ABI decoding tools, or a hex to UTF-8 converter and some basic ABI knowledge. @@ -158,13 +158,13 @@ The original error will not be human-readable in an off-chain explorer because i ## Dependencies - Prefer not reinventing the wheel, especially if there is an Openzeppelin wheel. -- The `shared` folder can be treated as a first party dependency and it is recommend to check if some functionality might already be in there before either writing it yourself or adding a third party dependency. +- The `shared` folder can be treated as a first-party dependency and it is recommended to check if some functionality might already be in there before either writing it yourself or adding a third party dependency. - When we have reinvented the wheel already (like with ownership), it is OK to keep using these contracts. If there are clear benefits of using another standard like OZ, we can deprecate the custom implementation and start using the new standard in all new projects. Migration will not be required unless there are serious issues with the old implementation. - When the decision is made to use a new standard, it is no longer allowed to use the old standard for new projects. ### Vendor dependencies -- That’s it, vendor your Solidity dependencies. Supply chain attacks are all the rage these days. There is not yet a silver bullet for best way to vendor, it depends on the size of your project and your needs. You should be as explicit as possible about where the code comes from and make sure that this is enforced in some way; e.g. reference a hash. Some options: +- That’s it, vendor your Solidity dependencies. Supply chain attacks are all the rage these days. There is not yet a silver bullet for the best way to vendor, it depends on the size of your project and your needs. You should be as explicit as possible about where the code comes from and make sure that this is enforced in some way; e.g. reference a hash. Some options: - NPM packages work for repos already in the JavaScript ecosystem. If you go this route you should lock to a hash of the repo or use a proxy registry like GitHub Packages. - Copy and paste the code into a `vendor` directory. Record attribution of the code and license in the repo along with the commit or version that you pulled the code from. - Foundry uses git submodules for its dependencies. We only use the `forge-std` lib through submodules, we don’t import any non-Foundry-testing code through this method. @@ -174,7 +174,7 @@ The original error will not be human-readable in an off-chain explorer because i ### Transferring Ownership -- When transferring control, whether it is of a token or a role in a contract, prefer "safe ownership" transfer patterns where the recipient must accept ownership. This avoids accidentally burning the control. This is also inline with the secure pattern of [prefer pull over push](https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls). +- When transferring control, whether it is of a token or a role in a contract, prefer "safe ownership" transfer patterns where the recipient must accept ownership. This avoids accidentally burning the control. This is also in line with the secure pattern of [prefer pull over push](https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls). ### Call with Exact Gas @@ -192,7 +192,7 @@ The original error will not be human-readable in an off-chain explorer because i - Calling other contracts will also be costly - Common types to safely use are - uint40 for timestamps (or uint32 if you really need the space) - - uint96 for link, as there are only 1b link tokens + - uint96 for LINK, as there are only 1b LINK tokens - prefer `++i` over `i++` - If you’re unsure about golfing, ask in the #tech-solidity channel @@ -214,13 +214,13 @@ The original error will not be human-readable in an off-chain explorer because i ## Picking a Pragma -- If a contract or library is expected to be imported by outside parties then the pragma should be kept as loose as possible without sacrificing safety. We publish versions for every minor semver version of Solidity, and maintain a corresponding set of tests for each published version. +- If a contract or library is expected to be imported by outside parties then the pragma should be kept as loose as possible without sacrificing safety. We publish versions for every minor Semver version of Solidity and maintain a corresponding set of tests for each published version. - Examples: libraries, interfaces, abstract contracts, and contracts expected to be inherited from -- Otherwise, Solidity contracts should have a pragma which is locked to a specific version. +- Otherwise, Solidity contracts should have a pragma that is locked to a specific version. - Example: Most concrete contracts. -- Avoid changing pragmas after audit. Unless there is a bug that has affects your contract, then you should try to stick to a known good pragma. In practice this means we typically only support one (occasionally two) pragma for any “major”(minor by semver naming) Solidity version. +- Avoid changing pragmas after the audit. Unless there is a bug that affects your contract, then you should try to stick to a known good pragma. In practice, this means we typically only support one (occasionally two) pragma for any “major”(minor by Semver naming) Solidity version. - The current advised pragma is `0.8.19` or higher, lower versions should be avoided when starting a new project. Newer versions can be considered. -- All contracts should have a SPDX license identifier. If unsure about which one to pick, please consult with legal. Most older contracts have been MIT, but some of the newer products have been using BUSL-1.1 +- All contracts should have an SPDX license identifier. If unsure about which one to pick, please consult with legal. Most older contracts have been MIT, but some of the newer products have been using BUSL-1.1 ## Versioning @@ -262,7 +262,7 @@ contract SuperDuperAggregator is ITypeAndVersion { All contracts will expose a `typeAndVersion` constant. The string has the following format: `-` with the `-dev` part only being applicable to contracts that have not been fully released. -Try to fit it into 32 bytes to keep impact on contract sizes minimal. +Try to fit it into 32 bytes to keep the impact on contract sizes minimal. Solhint will complain about a public constant variable that isn’t FULL_CAPS without the solhint-disable comment. @@ -276,12 +276,12 @@ Solhint will complain about a public constant variable that isn’t FULL_CAPS wi # Rules -All rules have a `rule` tag which indicated how the rule is enforced. +All rules have a `rule` tag which indicates how the rule is enforced. ## Comments -- Comments should be in the `//` (default) or `///` (natspec) format, not the `/* */` format. +- Comments should be in the `//` (default) or `///` (Natspec) format, not the `/* */` format. - rule: `tbd` - Comments should follow [NatSpec](https://docs.soliditylang.org/en/latest/natspec-format.html) - rule: `tbd` @@ -290,7 +290,7 @@ All rules have a `rule` tag which indicated how the rule is enforced. - Imports should always be explicit - rule: `no-global-import` -- Imports have follow the following format: +- Imports have to follow the following format: - rule: `tbd` ```solidity @@ -321,7 +321,7 @@ import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ All contract variables should be private by default. Getters should be explicitly written and documented when you want to expose a variable publicly. Whether a getter function reads from storage, a constant, or calculates a value from somewhere else, that’s all implementation details that should not be exposed to the consumer by casing or other conventions. -rule: tbd +rule: `tbd` ### Naming and Casing @@ -380,6 +380,14 @@ rule: `gas-custom-errors` ## Interfaces +### Purpose + +Interfaces separate NatSpec from contract logic, requiring readers to do more work to understand the code. For this reason, you shouldn’t create an interface by default. + +If created, interfaces should have a documented purpose. For example, an interface is useful if 3rd party on-chain contracts will interact with your contract. CCIP’s [`IRouterClient` interface](https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/ccip/interfaces/IRouterClient.sol) is a good example here. + +### Naming + Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). rule: `interface-starts-with-i` diff --git a/contracts/gas-snapshots/keystone.gas-snapshot b/contracts/gas-snapshots/keystone.gas-snapshot deleted file mode 100644 index 6797bd77e20..00000000000 --- a/contracts/gas-snapshots/keystone.gas-snapshot +++ /dev/null @@ -1,2 +0,0 @@ -KeystoneForwarderTest:test_abi_partial_decoding_works() (gas: 5123) -KeystoneForwarderTest:test_it_works() (gas: 996215) \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_keystone b/contracts/scripts/native_solc_compile_all_keystone index 49bd6527843..1530b307dbd 100755 --- a/contracts/scripts/native_solc_compile_all_keystone +++ b/contracts/scripts/native_solc_compile_all_keystone @@ -28,5 +28,6 @@ compileContract () { "$ROOT"/contracts/src/v0.8/"$1" } +compileContract keystone/CapabilityRegistry.sol compileContract keystone/KeystoneForwarder.sol compileContract keystone/OCR3Capability.sol diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol index 66761737e8f..90fdd82bfe7 100644 --- a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol @@ -306,6 +306,7 @@ interface AutomationRegistryBase2_3 { uint32 gasFeePPB; uint24 flatFeeMilliCents; address priceFeed; + uint8 decimals; uint256 fallbackPrice; uint96 minSpend; } @@ -404,5 +405,5 @@ interface IAutomationV21PlusCommon { // THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: /* -[{"inputs":[{"internalType":"contract AutomationRegistryLogicA2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientLinkLiquidity","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"MustSettleOffchain","type":"error"},{"inputs":[],"name":"MustSettleOnchain","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"overrides","type":"tuple"}],"name":"BillingConfigOverridden","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BillingConfigOverrideRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"payments","type":"uint256[]"}],"name":"NOPsSettledOffchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20","name":"billingToken","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicC2_3","name":"logicC","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"billingOverrides","type":"tuple"}],"name":"setBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20Fees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkUSDFeed","type":"address"},{"internalType":"address","name":"nativeUSDFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"},{"internalType":"address","name":"allowedReadOnlyAddress","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"payoutMode","type":"uint8"},{"internalType":"address","name":"wrappedNativeTokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableOffchainPayments","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowedReadOnlyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getBillingTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getChainModule","outputs":[{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFallbackNativePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHotVars","outputs":[{"components":[{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reentrancyGuard","type":"bool"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.HotVars","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"contract IERC20","name":"billingToken","type":"address"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumUpkeeps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutMode","outputs":[{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReorgProtectionEnabled","outputs":[{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"billingToken","type":"address"}],"name":"getReserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct IAutomationV21PlusCommon.StateLegacy","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct IAutomationV21PlusCommon.OnchainConfigLegacy","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStorage","outputs":[{"components":[{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"}],"internalType":"struct AutomationRegistryBase2_3.Storage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitCalldataFixedBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransmitCalldataPerSignerBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct IAutomationV21PlusCommon.UpkeepInfoLegacy","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleNOPsOffchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"supportsBillingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] +[{"inputs":[{"internalType":"contract AutomationRegistryLogicA2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientLinkLiquidity","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"MustSettleOffchain","type":"error"},{"inputs":[],"name":"MustSettleOnchain","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"overrides","type":"tuple"}],"name":"BillingConfigOverridden","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BillingConfigOverrideRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"payments","type":"uint256[]"}],"name":"NOPsSettledOffchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20Metadata[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicC2_3","name":"logicC","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"billingOverrides","type":"tuple"}],"name":"setBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"asset","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20Fees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkUSDFeed","type":"address"},{"internalType":"address","name":"nativeUSDFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"},{"internalType":"address","name":"allowedReadOnlyAddress","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"payoutMode","type":"uint8"},{"internalType":"address","name":"wrappedNativeTokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableOffchainPayments","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowedReadOnlyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"}],"name":"getBillingTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20Metadata[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getChainModule","outputs":[{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFallbackNativePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHotVars","outputs":[{"components":[{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reentrancyGuard","type":"bool"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.HotVars","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumUpkeeps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutMode","outputs":[{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReorgProtectionEnabled","outputs":[{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getReserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct IAutomationV21PlusCommon.StateLegacy","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct IAutomationV21PlusCommon.OnchainConfigLegacy","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStorage","outputs":[{"components":[{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"}],"internalType":"struct AutomationRegistryBase2_3.Storage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitCalldataFixedBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransmitCalldataPerSignerBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct IAutomationV21PlusCommon.UpkeepInfoLegacy","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleNOPsOffchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"}],"name":"supportsBillingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] */ diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol index 5b03b2efeb1..dd371033023 100644 --- a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; interface IWrappedNative is IERC20 { function deposit() external payable; diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol index e840d8b7397..76b808d1f05 100644 --- a/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {BaseTest} from "./BaseTest.t.sol"; import {IAutomationRegistryMaster2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {AutomationRegistrar2_3} from "../v2_3/AutomationRegistrar2_3.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryBase2_3.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; @@ -51,8 +51,8 @@ contract RegisterUpkeep is SetUp { function testUSDToken_autoApproveOff_happy() external { vm.startPrank(UPKEEP_ADMIN); - uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken)); - usdToken.approve(address(registrar), amount); + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken18)); + usdToken18.approve(address(registrar), amount); registrar.registerUpkeep( AutomationRegistrar2_3.RegistrationParams({ @@ -61,7 +61,7 @@ contract RegisterUpkeep is SetUp { adminAddress: UPKEEP_ADMIN, gasLimit: 10_000, triggerType: 0, - billingToken: usdToken, + billingToken: usdToken18, name: "foobar", encryptedEmail: "", checkData: bytes("check data"), @@ -70,7 +70,7 @@ contract RegisterUpkeep is SetUp { }) ); - assertEq(usdToken.balanceOf(address(registrar)), amount); + assertEq(usdToken18.balanceOf(address(registrar)), amount); assertEq(registry.getNumUpkeeps(), 0); } @@ -106,8 +106,8 @@ contract RegisterUpkeep is SetUp { registrar.setTriggerConfig(0, AutomationRegistrar2_3.AutoApproveType.ENABLED_ALL, 1000); vm.startPrank(UPKEEP_ADMIN); - uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken)); - usdToken.approve(address(registrar), amount); + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken18)); + usdToken18.approve(address(registrar), amount); registrar.registerUpkeep( AutomationRegistrar2_3.RegistrationParams({ @@ -116,7 +116,7 @@ contract RegisterUpkeep is SetUp { adminAddress: UPKEEP_ADMIN, gasLimit: 10_000, triggerType: 0, - billingToken: usdToken, + billingToken: usdToken18, name: "foobar", encryptedEmail: "", checkData: bytes("check data"), @@ -125,8 +125,8 @@ contract RegisterUpkeep is SetUp { }) ); - assertEq(usdToken.balanceOf(address(registrar)), 0); - assertEq(usdToken.balanceOf(address(registry)), amount); + assertEq(usdToken18.balanceOf(address(registrar)), 0); + assertEq(usdToken18.balanceOf(address(registry)), amount); assertEq(registry.getNumUpkeeps(), 1); } diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol index ef58dbbe4be..4d2cfbbec36 100644 --- a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol @@ -7,7 +7,7 @@ import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryB import {AutomationRegistrar2_3 as Registrar} from "../v2_3/AutomationRegistrar2_3.sol"; import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; // forge test --match-path src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol @@ -23,27 +23,30 @@ contract SetUp is BaseTest { bytes internal constant offchainConfigBytes = abi.encode(1234, ZERO_ADDRESS); uint256 linkUpkeepID; - uint256 linkUpkeepID2; - uint256 usdUpkeepID; + uint256 linkUpkeepID2; // 2 upkeeps use the same billing token (LINK) to test migration scenario + uint256 usdUpkeepID18; // 1 upkeep uses ERC20 token with 18 decimals + uint256 usdUpkeepID6; // 1 upkeep uses ERC20 token with 6 decimals uint256 nativeUpkeepID; function setUp() public virtual override { super.setUp(); - (registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); config = registry.getConfig(); vm.startPrank(OWNER); linkToken.approve(address(registry), type(uint256).max); - usdToken.approve(address(registry), type(uint256).max); + usdToken6.approve(address(registry), type(uint256).max); + usdToken18.approve(address(registry), type(uint256).max); weth.approve(address(registry), type(uint256).max); vm.startPrank(UPKEEP_ADMIN); linkToken.approve(address(registry), type(uint256).max); - usdToken.approve(address(registry), type(uint256).max); + usdToken6.approve(address(registry), type(uint256).max); + usdToken18.approve(address(registry), type(uint256).max); weth.approve(address(registry), type(uint256).max); vm.startPrank(STRANGER); linkToken.approve(address(registry), type(uint256).max); - usdToken.approve(address(registry), type(uint256).max); + usdToken6.approve(address(registry), type(uint256).max); + usdToken18.approve(address(registry), type(uint256).max); weth.approve(address(registry), type(uint256).max); vm.stopPrank(); @@ -69,12 +72,23 @@ contract SetUp is BaseTest { "" ); - usdUpkeepID = registry.registerUpkeep( + usdUpkeepID18 = registry.registerUpkeep( address(TARGET1), config.maxPerformGas, UPKEEP_ADMIN, uint8(Trigger.CONDITION), - address(usdToken), + address(usdToken18), + "", + "", + "" + ); + + usdUpkeepID6 = registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(usdToken6), "", "", "" @@ -94,7 +108,8 @@ contract SetUp is BaseTest { vm.startPrank(OWNER); registry.addFunds(linkUpkeepID, registry.getMinBalanceForUpkeep(linkUpkeepID)); registry.addFunds(linkUpkeepID2, registry.getMinBalanceForUpkeep(linkUpkeepID2)); - registry.addFunds(usdUpkeepID, registry.getMinBalanceForUpkeep(usdUpkeepID)); + registry.addFunds(usdUpkeepID18, registry.getMinBalanceForUpkeep(usdUpkeepID18)); + registry.addFunds(usdUpkeepID6, registry.getMinBalanceForUpkeep(usdUpkeepID6)); registry.addFunds(nativeUpkeepID, registry.getMinBalanceForUpkeep(nativeUpkeepID)); vm.stopPrank(); } @@ -174,21 +189,21 @@ contract AddFunds is SetUp { vm.startPrank(UPKEEP_ADMIN); uint256 startLINKRegistryBalance = linkToken.balanceOf(address(registry)); - uint256 startUSDRegistryBalance = usdToken.balanceOf(address(registry)); + uint256 startUSDRegistryBalance = usdToken18.balanceOf(address(registry)); uint256 startLinkUpkeepBalance = registry.getBalance(linkUpkeepID); - uint256 startUSDUpkeepBalance = registry.getBalance(usdUpkeepID); + uint256 startUSDUpkeepBalance = registry.getBalance(usdUpkeepID18); registry.addFunds(linkUpkeepID, 1); assertEq(registry.getBalance(linkUpkeepID), startLinkUpkeepBalance + 1); - assertEq(registry.getBalance(usdUpkeepID), startUSDRegistryBalance); + assertEq(registry.getBalance(usdUpkeepID18), startUSDRegistryBalance); assertEq(linkToken.balanceOf(address(registry)), startLINKRegistryBalance + 1); - assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance); + assertEq(usdToken18.balanceOf(address(registry)), startUSDUpkeepBalance); - registry.addFunds(usdUpkeepID, 2); + registry.addFunds(usdUpkeepID18, 2); assertEq(registry.getBalance(linkUpkeepID), startLinkUpkeepBalance + 1); - assertEq(registry.getBalance(usdUpkeepID), startUSDRegistryBalance + 2); + assertEq(registry.getBalance(usdUpkeepID18), startUSDRegistryBalance + 2); assertEq(linkToken.balanceOf(address(registry)), startLINKRegistryBalance + 1); - assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance + 2); + assertEq(usdToken18.balanceOf(address(registry)), startUSDUpkeepBalance + 2); } function test_emitsAnEvent() public { @@ -258,10 +273,10 @@ contract Withdraw is SetUp { } function test_WithdrawERC20Fees_RespectsReserveAmount() public { - assertEq(registry.getBalance(usdUpkeepID), registry.getReserveAmount(address(usdToken))); + assertEq(registry.getBalance(usdUpkeepID18), registry.getReserveAmount(address(usdToken18))); vm.startPrank(FINANCE_ADMIN); vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1)); - registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); + registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1); } function test_WithdrawERC20Fees_RevertsWhen_AttemptingToWithdrawLINK() public { @@ -273,35 +288,35 @@ contract Withdraw is SetUp { } function test_WithdrawERC20Fees_RevertsWhen_LinkAvailableForPaymentIsNegative() public { - _transmit(usdUpkeepID, registry); // adds USD token to finance withdrawable, and gives NOPs a LINK balance + _transmit(usdUpkeepID18, registry); // adds USD token to finance withdrawable, and gives NOPs a LINK balance require(registry.linkAvailableForPayment() < 0, "linkAvailableForPayment should be negative"); vm.expectRevert(Registry.InsufficientLinkLiquidity.selector); vm.prank(FINANCE_ADMIN); - registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); // should revert + registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1); // should revert _mintLink(address(registry), uint256(registry.linkAvailableForPayment() * -10)); // top up LINK liquidity pool vm.prank(FINANCE_ADMIN); - registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); // now finance can withdraw + registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1); // now finance can withdraw } function testWithdrawERC20FeeSuccess() public { // deposit excess USDToken to the registry (this goes to the "finance withdrawable" pool be default) - uint256 startReserveAmount = registry.getReserveAmount(address(usdToken)); - uint256 startAmount = usdToken.balanceOf(address(registry)); - _mintERC20(address(registry), 1e10); + uint256 startReserveAmount = registry.getReserveAmount(address(usdToken18)); + uint256 startAmount = usdToken18.balanceOf(address(registry)); + _mintERC20_18Decimals(address(registry), 1e10); // depositing shouldn't change reserve amount - assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount); + assertEq(registry.getReserveAmount(address(usdToken18)), startReserveAmount); vm.startPrank(FINANCE_ADMIN); // try to withdraw 1 USDToken - registry.withdrawERC20Fees(address(usdToken), aMockAddress, 1); + registry.withdrawERC20Fees(address(usdToken18), aMockAddress, 1); vm.stopPrank(); - assertEq(usdToken.balanceOf(address(aMockAddress)), 1); - assertEq(usdToken.balanceOf(address(registry)), startAmount + 1e10 - 1); - assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount); + assertEq(usdToken18.balanceOf(address(aMockAddress)), 1); + assertEq(usdToken18.balanceOf(address(registry)), startAmount + 1e10 - 1); + assertEq(registry.getReserveAmount(address(usdToken18)), startReserveAmount); } } @@ -343,7 +358,7 @@ contract SetConfig is SetUp { (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails(); assertEq(configCount, 1); - address billingTokenAddress = address(0x1111111111111111111111111111111111111111); + address billingTokenAddress = address(usdToken18); address[] memory billingTokens = new address[](1); billingTokens[0] = billingTokenAddress; @@ -351,9 +366,10 @@ contract SetConfig is SetUp { billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_000, flatFeeMilliCents: 20_000, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 2_000_000_000, // $20 - minSpend: 100_000 + minSpend: 100_000, + decimals: 18 }); bytes memory onchainConfigBytes = abi.encode(cfg); @@ -402,7 +418,7 @@ contract SetConfig is SetUp { AutomationRegistryBase2_3.BillingConfig memory config = registry.getBillingTokenConfig(billingTokenAddress); assertEq(config.gasFeePPB, 5_000); assertEq(config.flatFeeMilliCents, 20_000); - assertEq(config.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config.priceFeed, address(USDTOKEN_USD_FEED)); assertEq(config.minSpend, 100_000); address[] memory tokens = registry.getBillingTokens(); @@ -413,8 +429,8 @@ contract SetConfig is SetUp { (uint32 configCount, , ) = registry.latestConfigDetails(); assertEq(configCount, 1); - address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); - address billingTokenAddress2 = address(0x1111111111111111111111111111111111111112); + address billingTokenAddress1 = address(linkToken); + address billingTokenAddress2 = address(usdToken18); address[] memory billingTokens = new address[](2); billingTokens[0] = billingTokenAddress1; billingTokens[1] = billingTokenAddress2; @@ -423,16 +439,18 @@ contract SetConfig is SetUp { billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, flatFeeMilliCents: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 100, - minSpend: 100 + minSpend: 100, + decimals: 18 }); billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, flatFeeMilliCents: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 200, - minSpend: 200 + minSpend: 200, + decimals: 18 }); bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs); @@ -455,14 +473,14 @@ contract SetConfig is SetUp { AutomationRegistryBase2_3.BillingConfig memory config1 = registry.getBillingTokenConfig(billingTokenAddress1); assertEq(config1.gasFeePPB, 5_001); assertEq(config1.flatFeeMilliCents, 20_001); - assertEq(config1.priceFeed, 0x2222222222222222222222222222222222222221); + assertEq(config1.priceFeed, address(USDTOKEN_USD_FEED)); assertEq(config1.fallbackPrice, 100); assertEq(config1.minSpend, 100); AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2); assertEq(config2.gasFeePPB, 5_002); assertEq(config2.flatFeeMilliCents, 20_002); - assertEq(config2.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config2.priceFeed, address(USDTOKEN_USD_FEED)); assertEq(config2.fallbackPrice, 200); assertEq(config2.minSpend, 200); @@ -475,7 +493,7 @@ contract SetConfig is SetUp { assertEq(configCount, 1); // BillingConfig1 - address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); + address billingTokenAddress1 = address(usdToken18); address[] memory billingTokens1 = new address[](1); billingTokens1[0] = billingTokenAddress1; @@ -483,15 +501,16 @@ contract SetConfig is SetUp { billingConfigs1[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, flatFeeMilliCents: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 100, - minSpend: 100 + minSpend: 100, + decimals: 18 }); bytes memory onchainConfigBytesWithBilling1 = abi.encode(cfg, billingTokens1, billingConfigs1); // BillingConfig2 - address billingTokenAddress2 = address(0x1111111111111111111111111111111111111112); + address billingTokenAddress2 = address(usdToken18); address[] memory billingTokens2 = new address[](1); billingTokens2[0] = billingTokenAddress2; @@ -499,9 +518,10 @@ contract SetConfig is SetUp { billingConfigs2[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, flatFeeMilliCents: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 200, - minSpend: 200 + minSpend: 200, + decimals: 18 }); bytes memory onchainConfigBytesWithBilling2 = abi.encode(cfg, billingTokens2, billingConfigs2); @@ -535,7 +555,7 @@ contract SetConfig is SetUp { AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2); assertEq(config2.gasFeePPB, 5_002); assertEq(config2.flatFeeMilliCents, 20_002); - assertEq(config2.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config2.priceFeed, address(USDTOKEN_USD_FEED)); assertEq(config2.fallbackPrice, 200); assertEq(config2.minSpend, 200); @@ -547,8 +567,8 @@ contract SetConfig is SetUp { (uint32 configCount, , ) = registry.latestConfigDetails(); assertEq(configCount, 1); - address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); - address billingTokenAddress2 = address(0x1111111111111111111111111111111111111111); + address billingTokenAddress1 = address(linkToken); + address billingTokenAddress2 = address(linkToken); address[] memory billingTokens = new address[](2); billingTokens[0] = billingTokenAddress1; billingTokens[1] = billingTokenAddress2; @@ -557,16 +577,18 @@ contract SetConfig is SetUp { billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, flatFeeMilliCents: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 100, - minSpend: 100 + minSpend: 100, + decimals: 18 }); billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, flatFeeMilliCents: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 200, - minSpend: 200 + minSpend: 200, + decimals: 18 }); bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs); @@ -591,9 +613,10 @@ contract SetConfig is SetUp { billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_000, flatFeeMilliCents: 20_000, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 2_000_000_000, // $20 - minSpend: 100_000 + minSpend: 100_000, + decimals: 18 }); // deploy registry with OFF_CHAIN payout mode @@ -612,13 +635,40 @@ contract SetConfig is SetUp { ); } + function testSetConfigRevertDueToInvalidDecimals() public { + address[] memory billingTokens = new address[](1); + billingTokens[0] = address(linkToken); + + AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](1); + billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000, + priceFeed: address(USDTOKEN_USD_FEED), + fallbackPrice: 2_000_000_000, // $20 + minSpend: 100_000, + decimals: 6 // link token should have 18 decimals + }); + + vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector)); + registry.setConfigTypeSafe( + SIGNERS, + TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes, + billingTokens, + billingConfigs + ); + } + function testSetConfigWithNewTransmittersSuccess() public { registry = deployRegistry(AutoBase.PayoutMode.OFF_CHAIN); (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails(); assertEq(configCount, 0); - address billingTokenAddress = address(0x1111111111111111111111111111111111111111); + address billingTokenAddress = address(usdToken18); address[] memory billingTokens = new address[](1); billingTokens[0] = billingTokenAddress; @@ -626,9 +676,10 @@ contract SetConfig is SetUp { billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_000, flatFeeMilliCents: 20_000, - priceFeed: 0x2222222222222222222222222222222222222222, + priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 2_000_000_000, // $20 - minSpend: 100_000 + minSpend: 100_000, + decimals: 18 }); bytes memory onchainConfigBytes = abi.encode(cfg); @@ -790,10 +841,10 @@ contract NOPsSettlement is SetUp { (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); // register an upkeep and add funds - uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); - _mintERC20(UPKEEP_ADMIN, 1e20); + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", ""); + _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20); vm.startPrank(UPKEEP_ADMIN); - usdToken.approve(address(registry), 1e20); + usdToken18.approve(address(registry), 1e20); registry.addFunds(id, 1e20); // manually create a transmit so transmitters earn some rewards @@ -831,10 +882,10 @@ contract NOPsSettlement is SetUp { (Registry registry, Registrar registrar) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); // register an upkeep and add funds - uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); - _mintERC20(UPKEEP_ADMIN, 1e20); + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", ""); + _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20); vm.startPrank(UPKEEP_ADMIN); - usdToken.approve(address(registry), 1e20); + usdToken18.approve(address(registry), 1e20); registry.addFunds(id, 1e20); // manually create a transmit so TRANSMITTERS earn some rewards @@ -943,10 +994,10 @@ contract NOPsSettlement is SetUp { (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); // register an upkeep and add funds - uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); - _mintERC20(UPKEEP_ADMIN, 1e20); + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", ""); + _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20); vm.startPrank(UPKEEP_ADMIN); - usdToken.approve(address(registry), 1e20); + usdToken18.approve(address(registry), 1e20); registry.addFunds(id, 1e20); // manually create a transmit so transmitters earn some rewards @@ -981,10 +1032,10 @@ contract NOPsSettlement is SetUp { (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); // register an upkeep and add funds - uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); - _mintERC20(UPKEEP_ADMIN, 1e20); + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", ""); + _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20); vm.startPrank(UPKEEP_ADMIN); - usdToken.approve(address(registry), 1e20); + usdToken18.approve(address(registry), 1e20); registry.addFunds(id, 1e20); // manually call transmit so transmitters earn some rewards @@ -1025,10 +1076,10 @@ contract NOPsSettlement is SetUp { function _configureWithNewTransmitters(Registry registry, Registrar registrar) internal { IERC20[] memory billingTokens = new IERC20[](1); - billingTokens[0] = IERC20(address(usdToken)); + billingTokens[0] = IERC20(address(usdToken18)); uint256[] memory minRegistrationFees = new uint256[](billingTokens.length); - minRegistrationFees[0] = 100000000000000000000; // 100 USD + minRegistrationFees[0] = 100e18; // 100 USD address[] memory billingTokenAddresses = new address[](billingTokens.length); for (uint256 i = 0; i < billingTokens.length; i++) { @@ -1041,8 +1092,9 @@ contract NOPsSettlement is SetUp { gasFeePPB: 10_000_000, // 15% flatFeeMilliCents: 2_000, // 2 cents priceFeed: address(USDTOKEN_USD_FEED), - fallbackPrice: 100_000_000, // $1 - minSpend: 1000000000000000000 // 1 USD + fallbackPrice: 1e8, // $1 + minSpend: 1e18, // 1 USD + decimals: 18 }); address[] memory registrars = new address[](1); @@ -1245,7 +1297,7 @@ contract OnTokenTransfer is SetUp { function test_RevertsWhen_TheUpkeepDoesNotUseLINKAsItsBillingToken() public { vm.startPrank(address(linkToken)); vm.expectRevert(Registry.InvalidToken.selector); - registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(usdUpkeepID)); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(usdUpkeepID18)); } function test_Happy() public { @@ -1257,20 +1309,42 @@ contract OnTokenTransfer is SetUp { } contract GetMinBalanceForUpkeep is SetUp { - function test_accountsForFlatFee() public { + function test_accountsForFlatFee_with18Decimals() public { // set fee to 0 - AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken)); + AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken18)); usdTokenConfig.flatFeeMilliCents = 0; - _updateBillingTokenConfig(registry, address(usdToken), usdTokenConfig); + _updateBillingTokenConfig(registry, address(usdToken18), usdTokenConfig); - uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID); + uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID18); // set fee to non-zero usdTokenConfig.flatFeeMilliCents = 100; - _updateBillingTokenConfig(registry, address(usdToken), usdTokenConfig); + _updateBillingTokenConfig(registry, address(usdToken18), usdTokenConfig); - uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID); - assertEq(minBalanceAfter, minBalanceBefore + (uint256(usdTokenConfig.flatFeeMilliCents) * 1e13)); + uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID18); + assertEq( + minBalanceAfter, + minBalanceBefore + ((uint256(usdTokenConfig.flatFeeMilliCents) * 1e13) / 10 ** (18 - usdTokenConfig.decimals)) + ); + } + + function test_accountsForFlatFee_with6Decimals() public { + // set fee to 0 + AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken6)); + usdTokenConfig.flatFeeMilliCents = 0; + _updateBillingTokenConfig(registry, address(usdToken6), usdTokenConfig); + + uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID6); + + // set fee to non-zero + usdTokenConfig.flatFeeMilliCents = 100; + _updateBillingTokenConfig(registry, address(usdToken6), usdTokenConfig); + + uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID6); + assertEq( + minBalanceAfter, + minBalanceBefore + ((uint256(usdTokenConfig.flatFeeMilliCents) * 1e13) / 10 ** (18 - usdTokenConfig.decimals)) + ); } } @@ -1346,29 +1420,29 @@ contract Transmit is SetUp { function test_handlesMixedBatchOfBillingTokens() external { uint256[] memory prevUpkeepBalances = new uint256[](3); prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); - prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID18); prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); uint256[] memory prevTokenBalances = new uint256[](3); prevTokenBalances[0] = linkToken.balanceOf(address(registry)); - prevTokenBalances[1] = usdToken.balanceOf(address(registry)); + prevTokenBalances[1] = usdToken18.balanceOf(address(registry)); prevTokenBalances[2] = weth.balanceOf(address(registry)); uint256[] memory prevReserveBalances = new uint256[](3); prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); - prevReserveBalances[1] = registry.getReserveAmount(address(usdToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(usdToken18)); prevReserveBalances[2] = registry.getReserveAmount(address(weth)); uint256[] memory upkeepIDs = new uint256[](3); upkeepIDs[0] = linkUpkeepID; - upkeepIDs[1] = usdUpkeepID; + upkeepIDs[1] = usdUpkeepID18; upkeepIDs[2] = nativeUpkeepID; // do the thing _transmit(upkeepIDs, registry); // assert upkeep balances have decreased require(prevUpkeepBalances[0] > registry.getBalance(linkUpkeepID), "link upkeep balance should have decreased"); - require(prevUpkeepBalances[1] > registry.getBalance(usdUpkeepID), "usd upkeep balance should have decreased"); + require(prevUpkeepBalances[1] > registry.getBalance(usdUpkeepID18), "usd upkeep balance should have decreased"); require(prevUpkeepBalances[2] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); // assert token balances have not changed assertEq(prevTokenBalances[0], linkToken.balanceOf(address(registry))); - assertEq(prevTokenBalances[1], usdToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], usdToken18.balanceOf(address(registry))); assertEq(prevTokenBalances[2], weth.balanceOf(address(registry))); // assert reserve amounts have adjusted accordingly require( @@ -1376,7 +1450,7 @@ contract Transmit is SetUp { "usd reserve amount should have increased" ); // link reserve amount increases in value equal to the decrease of the other reserve amounts require( - prevReserveBalances[1] > registry.getReserveAmount(address(usdToken)), + prevReserveBalances[1] > registry.getReserveAmount(address(usdToken18)), "usd reserve amount should have decreased" ); require( @@ -1398,7 +1472,7 @@ contract MigrateReceive is SetUp { (newRegistry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); idsToMigrate.push(linkUpkeepID); idsToMigrate.push(linkUpkeepID2); - idsToMigrate.push(usdUpkeepID); + idsToMigrate.push(usdUpkeepID18); idsToMigrate.push(nativeUpkeepID); registry.setPeerRegistryMigrationPermission(address(newRegistry), 1); newRegistry.setPeerRegistryMigrationPermission(address(registry), 2); @@ -1454,7 +1528,7 @@ contract MigrateReceive is SetUp { vm.startPrank(UPKEEP_ADMIN); // add some changes in upkeep data to the mix - registry.pauseUpkeep(usdUpkeepID); + registry.pauseUpkeep(usdUpkeepID18); registry.setUpkeepTriggerConfig(linkUpkeepID, randomBytes(100)); registry.setUpkeepCheckData(nativeUpkeepID, randomBytes(25)); @@ -1462,25 +1536,25 @@ contract MigrateReceive is SetUp { uint256[] memory prevUpkeepBalances = new uint256[](4); prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID2); - prevUpkeepBalances[2] = registry.getBalance(usdUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(usdUpkeepID18); prevUpkeepBalances[3] = registry.getBalance(nativeUpkeepID); uint256[] memory prevReserveBalances = new uint256[](3); prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); - prevReserveBalances[1] = registry.getReserveAmount(address(usdToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(usdToken18)); prevReserveBalances[2] = registry.getReserveAmount(address(weth)); uint256[] memory prevTokenBalances = new uint256[](3); prevTokenBalances[0] = linkToken.balanceOf(address(registry)); - prevTokenBalances[1] = usdToken.balanceOf(address(registry)); + prevTokenBalances[1] = usdToken18.balanceOf(address(registry)); prevTokenBalances[2] = weth.balanceOf(address(registry)); bytes[] memory prevUpkeepData = new bytes[](4); prevUpkeepData[0] = abi.encode(registry.getUpkeep(linkUpkeepID)); prevUpkeepData[1] = abi.encode(registry.getUpkeep(linkUpkeepID2)); - prevUpkeepData[2] = abi.encode(registry.getUpkeep(usdUpkeepID)); + prevUpkeepData[2] = abi.encode(registry.getUpkeep(usdUpkeepID18)); prevUpkeepData[3] = abi.encode(registry.getUpkeep(nativeUpkeepID)); bytes[] memory prevUpkeepTriggerData = new bytes[](4); prevUpkeepTriggerData[0] = registry.getUpkeepTriggerConfig(linkUpkeepID); prevUpkeepTriggerData[1] = registry.getUpkeepTriggerConfig(linkUpkeepID2); - prevUpkeepTriggerData[2] = registry.getUpkeepTriggerConfig(usdUpkeepID); + prevUpkeepTriggerData[2] = registry.getUpkeepTriggerConfig(usdUpkeepID18); prevUpkeepTriggerData[3] = registry.getUpkeepTriggerConfig(nativeUpkeepID); // event expectations @@ -1489,7 +1563,7 @@ contract MigrateReceive is SetUp { vm.expectEmit(address(registry)); emit UpkeepMigrated(linkUpkeepID2, prevUpkeepBalances[1], address(newRegistry)); vm.expectEmit(address(registry)); - emit UpkeepMigrated(usdUpkeepID, prevUpkeepBalances[2], address(newRegistry)); + emit UpkeepMigrated(usdUpkeepID18, prevUpkeepBalances[2], address(newRegistry)); vm.expectEmit(address(registry)); emit UpkeepMigrated(nativeUpkeepID, prevUpkeepBalances[3], address(newRegistry)); vm.expectEmit(address(newRegistry)); @@ -1497,7 +1571,7 @@ contract MigrateReceive is SetUp { vm.expectEmit(address(newRegistry)); emit UpkeepReceived(linkUpkeepID2, prevUpkeepBalances[1], address(registry)); vm.expectEmit(address(newRegistry)); - emit UpkeepReceived(usdUpkeepID, prevUpkeepBalances[2], address(registry)); + emit UpkeepReceived(usdUpkeepID18, prevUpkeepBalances[2], address(registry)); vm.expectEmit(address(newRegistry)); emit UpkeepReceived(nativeUpkeepID, prevUpkeepBalances[3], address(registry)); @@ -1507,11 +1581,11 @@ contract MigrateReceive is SetUp { // assert upkeep balances have been migrated assertEq(registry.getBalance(linkUpkeepID), 0); assertEq(registry.getBalance(linkUpkeepID2), 0); - assertEq(registry.getBalance(usdUpkeepID), 0); + assertEq(registry.getBalance(usdUpkeepID18), 0); assertEq(registry.getBalance(nativeUpkeepID), 0); assertEq(newRegistry.getBalance(linkUpkeepID), prevUpkeepBalances[0]); assertEq(newRegistry.getBalance(linkUpkeepID2), prevUpkeepBalances[1]); - assertEq(newRegistry.getBalance(usdUpkeepID), prevUpkeepBalances[2]); + assertEq(newRegistry.getBalance(usdUpkeepID18), prevUpkeepBalances[2]); assertEq(newRegistry.getBalance(nativeUpkeepID), prevUpkeepBalances[3]); // assert reserve balances have been adjusted @@ -1519,15 +1593,15 @@ contract MigrateReceive is SetUp { newRegistry.getReserveAmount(address(linkToken)), newRegistry.getBalance(linkUpkeepID) + newRegistry.getBalance(linkUpkeepID2) ); - assertEq(newRegistry.getReserveAmount(address(usdToken)), newRegistry.getBalance(usdUpkeepID)); + assertEq(newRegistry.getReserveAmount(address(usdToken18)), newRegistry.getBalance(usdUpkeepID18)); assertEq(newRegistry.getReserveAmount(address(weth)), newRegistry.getBalance(nativeUpkeepID)); assertEq( newRegistry.getReserveAmount(address(linkToken)), prevReserveBalances[0] - registry.getReserveAmount(address(linkToken)) ); assertEq( - newRegistry.getReserveAmount(address(usdToken)), - prevReserveBalances[1] - registry.getReserveAmount(address(usdToken)) + newRegistry.getReserveAmount(address(usdToken18)), + prevReserveBalances[1] - registry.getReserveAmount(address(usdToken18)) ); assertEq( newRegistry.getReserveAmount(address(weth)), @@ -1539,20 +1613,23 @@ contract MigrateReceive is SetUp { linkToken.balanceOf(address(newRegistry)), newRegistry.getBalance(linkUpkeepID) + newRegistry.getBalance(linkUpkeepID2) ); - assertEq(usdToken.balanceOf(address(newRegistry)), newRegistry.getBalance(usdUpkeepID)); + assertEq(usdToken18.balanceOf(address(newRegistry)), newRegistry.getBalance(usdUpkeepID18)); assertEq(weth.balanceOf(address(newRegistry)), newRegistry.getBalance(nativeUpkeepID)); assertEq(linkToken.balanceOf(address(registry)), prevTokenBalances[0] - linkToken.balanceOf(address(newRegistry))); - assertEq(usdToken.balanceOf(address(registry)), prevTokenBalances[1] - usdToken.balanceOf(address(newRegistry))); + assertEq( + usdToken18.balanceOf(address(registry)), + prevTokenBalances[1] - usdToken18.balanceOf(address(newRegistry)) + ); assertEq(weth.balanceOf(address(registry)), prevTokenBalances[2] - weth.balanceOf(address(newRegistry))); // assert upkeep data matches assertEq(prevUpkeepData[0], abi.encode(newRegistry.getUpkeep(linkUpkeepID))); assertEq(prevUpkeepData[1], abi.encode(newRegistry.getUpkeep(linkUpkeepID2))); - assertEq(prevUpkeepData[2], abi.encode(newRegistry.getUpkeep(usdUpkeepID))); + assertEq(prevUpkeepData[2], abi.encode(newRegistry.getUpkeep(usdUpkeepID18))); assertEq(prevUpkeepData[3], abi.encode(newRegistry.getUpkeep(nativeUpkeepID))); assertEq(prevUpkeepTriggerData[0], newRegistry.getUpkeepTriggerConfig(linkUpkeepID)); assertEq(prevUpkeepTriggerData[1], newRegistry.getUpkeepTriggerConfig(linkUpkeepID2)); - assertEq(prevUpkeepTriggerData[2], newRegistry.getUpkeepTriggerConfig(usdUpkeepID)); + assertEq(prevUpkeepTriggerData[2], newRegistry.getUpkeepTriggerConfig(usdUpkeepID18)); assertEq(prevUpkeepTriggerData[3], newRegistry.getUpkeepTriggerConfig(nativeUpkeepID)); vm.stopPrank(); diff --git a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol index eae07a8bab7..5ae9a29fc15 100644 --- a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol @@ -5,6 +5,7 @@ import "forge-std/Test.sol"; import {LinkToken} from "../../../shared/token/ERC677/LinkToken.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; +import {ERC20Mock6Decimals} from "../../mocks/ERC20Mock6Decimals.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; import {UpkeepTranscoder5_0 as Transcoder} from "../v2_3/UpkeepTranscoder5_0.sol"; @@ -16,7 +17,7 @@ import {AutomationRegistryLogicC2_3} from "../v2_3/AutomationRegistryLogicC2_3.s import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {AutomationRegistrar2_3} from "../v2_3/AutomationRegistrar2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {MockUpkeep} from "../../mocks/MockUpkeep.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; import {WETH9} from "./WETH9.sol"; @@ -40,7 +41,8 @@ contract BaseTest is Test { // contracts LinkToken internal linkToken; - ERC20Mock internal usdToken; + ERC20Mock6Decimals internal usdToken6; + ERC20Mock internal usdToken18; WETH9 internal weth; MockV3Aggregator internal LINK_USD_FEED; MockV3Aggregator internal NATIVE_USD_FEED; @@ -73,7 +75,8 @@ contract BaseTest is Test { vm.startPrank(OWNER); linkToken = new LinkToken(); linkToken.grantMintRole(OWNER); - usdToken = new ERC20Mock("MOCK_ERC20", "MOCK_ERC20", OWNER, 0); + usdToken18 = new ERC20Mock("MOCK_ERC20_18Decimals", "MOCK_ERC20_18Decimals", OWNER, 0); + usdToken6 = new ERC20Mock6Decimals("MOCK_ERC20_6Decimals", "MOCK_ERC20_6Decimals", OWNER, 0); weth = new WETH9(); LINK_USD_FEED = new MockV3Aggregator(8, 2_000_000_000); // $20 @@ -114,14 +117,22 @@ contract BaseTest is Test { vm.deal(UPKEEP_ADMIN, 100 ether); vm.deal(FINANCE_ADMIN, 100 ether); vm.deal(STRANGER, 100 ether); + linkToken.mint(OWNER, 1000e18); linkToken.mint(UPKEEP_ADMIN, 1000e18); linkToken.mint(FINANCE_ADMIN, 1000e18); linkToken.mint(STRANGER, 1000e18); - usdToken.mint(OWNER, 1000e18); - usdToken.mint(UPKEEP_ADMIN, 1000e18); - usdToken.mint(FINANCE_ADMIN, 1000e18); - usdToken.mint(STRANGER, 1000e18); + + usdToken18.mint(OWNER, 1000e18); + usdToken18.mint(UPKEEP_ADMIN, 1000e18); + usdToken18.mint(FINANCE_ADMIN, 1000e18); + usdToken18.mint(STRANGER, 1000e18); + + usdToken6.mint(OWNER, 1000e6); + usdToken6.mint(UPKEEP_ADMIN, 1000e6); + usdToken6.mint(FINANCE_ADMIN, 1000e6); + usdToken6.mint(STRANGER, 1000e6); + weth.mint(OWNER, 1000e18); weth.mint(UPKEEP_ADMIN, 1000e18); weth.mint(FINANCE_ADMIN, 1000e18); @@ -154,14 +165,16 @@ contract BaseTest is Test { ) internal returns (Registry, AutomationRegistrar2_3) { Registry registry = deployRegistry(payoutMode); - IERC20[] memory billingTokens = new IERC20[](3); - billingTokens[0] = IERC20(address(usdToken)); + IERC20[] memory billingTokens = new IERC20[](4); + billingTokens[0] = IERC20(address(usdToken18)); billingTokens[1] = IERC20(address(weth)); billingTokens[2] = IERC20(address(linkToken)); + billingTokens[3] = IERC20(address(usdToken6)); uint256[] memory minRegistrationFees = new uint256[](billingTokens.length); - minRegistrationFees[0] = 100000000000000000000; // 100 USD - minRegistrationFees[1] = 5000000000000000000; // 5 Native - minRegistrationFees[2] = 5000000000000000000; // 5 LINK + minRegistrationFees[0] = 100e18; // 100 USD + minRegistrationFees[1] = 5e18; // 5 Native + minRegistrationFees[2] = 5e18; // 5 LINK + minRegistrationFees[3] = 100e6; // 100 USD address[] memory billingTokenAddresses = new address[](billingTokens.length); for (uint256 i = 0; i < billingTokens.length; i++) { billingTokenAddresses[i] = address(billingTokens[i]); @@ -173,21 +186,32 @@ contract BaseTest is Test { flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents priceFeed: address(USDTOKEN_USD_FEED), fallbackPrice: 100_000_000, // $1 - minSpend: 1000000000000000000 // 1 USD + minSpend: 1e18, // 1 USD + decimals: 18 }); billingTokenConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15% flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents priceFeed: address(NATIVE_USD_FEED), fallbackPrice: 100_000_000, // $1 - minSpend: 5000000000000000000 // 5 Native + minSpend: 5e18, // 5 Native + decimals: 18 }); billingTokenConfigs[2] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: DEFAULT_GAS_FEE_PPB, // 10% flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents priceFeed: address(LINK_USD_FEED), fallbackPrice: 1_000_000_000, // $10 - minSpend: 1000000000000000000 // 1 LINK + minSpend: 1e18, // 1 LINK + decimals: 18 + }); + billingTokenConfigs[3] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15% + flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents + priceFeed: address(USDTOKEN_USD_FEED), + fallbackPrice: 1e8, // $1 + minSpend: 1e6, // 1 USD + decimals: 6 }); if (payoutMode == AutoBase.PayoutMode.OFF_CHAIN) { @@ -418,10 +442,10 @@ contract BaseTest is Test { linkToken.mint(recipient, amount); } - /// @dev mints USDToken to the recipient - function _mintERC20(address recipient, uint256 amount) internal { + /// @dev mints USDToken with 18 decimals to the recipient + function _mintERC20_18Decimals(address recipient, uint256 amount) internal { vm.prank(OWNER); - usdToken.mint(recipient, amount); + usdToken18.mint(recipient, amount); } /// @dev returns a pseudo-random 32 bytes 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 d4a6f90c313..ab9d7ae0b20 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 @@ -6,7 +6,7 @@ import {IAutomationRegistryMaster2_3} from "../interfaces/v2_3/IAutomationRegist import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol index d57a4ad6345..c95c2138f71 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol @@ -9,7 +9,7 @@ import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {Chainable} from "../../Chainable.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; import {OCR2Abstract} from "../../../shared/ocr2/OCR2Abstract.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** * @notice Registry for adding work for Chainlink nodes to perform on client 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 087d907ab44..275b25b28d0 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 @@ -11,7 +11,7 @@ import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Inte import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; import {KeeperCompatibleInterface} from "../../interfaces/KeeperCompatibleInterface.sol"; import {IChainModule} from "../../interfaces/IChainModule.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; @@ -58,8 +58,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { // tx itself, but since payment processing itself takes gas, and it needs the overhead as input, we use fixed constants // to account for gas used in payment processing. These values are calibrated using hardhat tests which simulates various cases and verifies that // the variables result in accurate estimation - uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_000; // Fixed overhead per tx - uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 9_000; // Overhead per upkeep performed in batch + uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_200; // Fixed overhead per tx + uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 9_200; // Overhead per upkeep performed in batch LinkTokenInterface internal immutable i_link; AggregatorV3Interface internal immutable i_linkUSDFeed; @@ -375,6 +375,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { uint32 gasFeePPB; uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167 AggregatorV3Interface priceFeed; + uint8 decimals; // 1st word, read in calculating BillingTokenPaymentParams uint256 fallbackPrice; // 2nd word only read if stale @@ -395,6 +396,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @dev this is a memory-only struct, so struct packing is less important */ struct BillingTokenPaymentParams { + uint8 decimals; uint32 gasFeePPB; uint24 flatFeeMilliCents; uint256 priceUSD; @@ -426,8 +428,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { /** * @notice struct containing receipt information about a payment or cost estimation - * @member gasCharge the amount to charge a user for gas spent - * @member premium the premium charged to the user, shared between all nodes + * @member gasCharge the amount to charge a user for gas spent using the billing token's native decimals + * @member premium the premium charged to the user, shared between all nodes, using the billing token's native decimals * @member gasReimbursementJuels the amount to reimburse a node for gas spent * @member premiumJuels the premium paid to NOPs, shared between all nodes */ @@ -633,6 +635,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { BillingConfig storage config = s_billingConfigs[billingToken]; paymentParams.flatFeeMilliCents = config.flatFeeMilliCents; paymentParams.gasFeePPB = config.gasFeePPB; + paymentParams.decimals = config.decimals; (, int256 feedValue, , uint256 timestamp, ) = config.priceFeed.latestRoundData(); if ( feedValue <= 0 || @@ -660,22 +663,38 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { HotVars memory hotVars, PaymentParams memory paymentParams ) internal view returns (PaymentReceipt memory receipt) { + uint256 decimals = paymentParams.billingTokenParams.decimals; uint256 gasWei = paymentParams.fastGasWei * hotVars.gasCeilingMultiplier; // in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier if (paymentParams.isTransaction && tx.gasprice < gasWei) { gasWei = tx.gasprice; } + // scaling factor is based on decimals of billing token, and applies to premium and gasCharge + uint256 numeratorScalingFactor = decimals > 18 ? 10 ** (decimals - 18) : 1; + uint256 denominatorScalingFactor = decimals < 18 ? 10 ** (18 - decimals) : 1; + + // gas calculation uint256 gasPaymentHexaicosaUSD = (gasWei * (paymentParams.gasLimit + paymentParams.gasOverhead) + paymentParams.l1CostWei) * paymentParams.nativeUSD; // gasPaymentHexaicosaUSD has an extra 8 zeros because of decimals on nativeUSD feed - receipt.gasCharge = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); // has units of attoBillingToken, or "wei" + // gasCharge is scaled by the billing token's decimals + receipt.gasCharge = SafeCast.toUint96( + (gasPaymentHexaicosaUSD * numeratorScalingFactor) / + (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor) + ); receipt.gasReimbursementJuels = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.linkUSD); + + // premium calculation uint256 flatFeeHexaicosaUSD = uint256(paymentParams.billingTokenParams.flatFeeMilliCents) * 1e21; // 1e13 for milliCents to attoUSD and 1e8 for attoUSD to hexaicosaUSD uint256 premiumHexaicosaUSD = ((((gasWei * paymentParams.gasLimit) + paymentParams.l1CostWei) * paymentParams.billingTokenParams.gasFeePPB * paymentParams.nativeUSD) / 1e9) + flatFeeHexaicosaUSD; - receipt.premium = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); + // premium is scaled by the billing token's decimals + receipt.premium = SafeCast.toUint96( + (premiumHexaicosaUSD * numeratorScalingFactor) / + (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor) + ); receipt.premiumJuels = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.linkUSD); return receipt; @@ -975,7 +994,9 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { PaymentReceipt memory receipt = _calculatePaymentAmount(hotVars, paymentParams); + // balance is in the token's native decimals uint96 balance = upkeep.balance; + // payment is in the token's native decimals uint96 payment = receipt.gasCharge + receipt.premium; // this shouldn't happen, but in rare edge cases, we charge the full balance in case the user @@ -1064,6 +1085,11 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { IERC20 token = billingTokens[i]; BillingConfig memory config = billingConfigs[i]; + // most ERC20 tokens are 18 decimals, priceFeed must be 8 decimals + if (config.decimals != token.decimals() || config.priceFeed.decimals() != 8) { + revert InvalidToken(); + } + // if LINK is a billing option, payout mode must be ON_CHAIN if (address(token) == address(i_link) && mode == PayoutMode.OFF_CHAIN) { revert InvalidToken(); diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol index c08d6a0469a..99fc97ce5ce 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol @@ -11,7 +11,7 @@ import {AutomationForwarder} from "../../AutomationForwarder.sol"; import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; import {UpkeepTranscoderInterfaceV2} from "../../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {MigratableKeeperRegistryInterfaceV2} from "../../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** 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 85d81e84b6f..d69d5e0bd96 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 @@ -6,7 +6,7 @@ import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contra import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {Chainable} from "../../Chainable.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol index ef6a70333e0..0a429730bdb 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol @@ -6,7 +6,7 @@ import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contra import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; import {IChainModule} from "../../interfaces/IChainModule.sol"; -import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IAutomationV21PlusCommon} from "../../interfaces/IAutomationV21PlusCommon.sol"; contract AutomationRegistryLogicC2_3 is AutomationRegistryBase2_3 { diff --git a/contracts/src/v0.8/automation/mocks/ERC20Mock6Decimals.sol b/contracts/src/v0.8/automation/mocks/ERC20Mock6Decimals.sol new file mode 100644 index 00000000000..63a61814e0d --- /dev/null +++ b/contracts/src/v0.8/automation/mocks/ERC20Mock6Decimals.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.8.0; + +import {ERC20Mock} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; + +// mock ERC20 with 6 decimals +contract ERC20Mock6Decimals is ERC20Mock { + constructor( + string memory name, + string memory symbol, + address initialAccount, + uint256 initialBalance + ) payable ERC20Mock(name, symbol, initialAccount, initialBalance) {} + + function decimals() public view virtual override returns (uint8) { + return 6; + } +} diff --git a/contracts/src/v0.8/keystone/CapabilityRegistry.sol b/contracts/src/v0.8/keystone/CapabilityRegistry.sol new file mode 100644 index 00000000000..7c870bed7fb --- /dev/null +++ b/contracts/src/v0.8/keystone/CapabilityRegistry.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; +import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol"; + +struct Capability { + // Capability type, e.g. "data-streams-reports" + // bytes32(string); validation regex: ^[a-z0-9_\-:]{1,32}$ + // Not "type" because that's a reserved keyword in Solidity. + bytes32 capabilityType; + // Semver, e.g., "1.2.3" + // bytes32(string); must be valid Semver + max 32 characters. + bytes32 version; +} + +contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface { + mapping(bytes32 => Capability) private s_capabilities; + + event CapabilityAdded(bytes32 indexed capabilityId); + + function typeAndVersion() external pure override returns (string memory) { + return "CapabilityRegistry 1.0.0"; + } + + function addCapability(Capability calldata capability) external onlyOwner { + bytes32 capabilityId = getCapabilityID(capability.capabilityType, capability.version); + s_capabilities[capabilityId] = capability; + emit CapabilityAdded(capabilityId); + } + + function getCapability(bytes32 capabilityID) public view returns (Capability memory) { + return s_capabilities[capabilityID]; + } + + /// @notice This functions returns a Capability ID packed into a bytes32 for cheaper access + /// @return A unique identifier for the capability + function getCapabilityID(bytes32 capabilityType, bytes32 version) public pure returns (bytes32) { + return keccak256(abi.encodePacked(capabilityType, version)); + } +} diff --git a/contracts/src/v0.8/keystone/KeystoneForwarder.sol b/contracts/src/v0.8/keystone/KeystoneForwarder.sol index b4a9501e8f4..e6e2675fa2d 100644 --- a/contracts/src/v0.8/keystone/KeystoneForwarder.sol +++ b/contracts/src/v0.8/keystone/KeystoneForwarder.sol @@ -10,6 +10,14 @@ import {Utils} from "./libraries/Utils.sol"; contract KeystoneForwarder is IForwarder, ConfirmedOwner, TypeAndVersionInterface { error ReentrantCall(); + /// @notice This error is returned when the data with report is invalid. + /// This can happen if the data is shorter than SELECTOR_LENGTH + REPORT_LENGTH. + /// @param data the data that was received + error InvalidData(bytes data); + + uint256 private constant SELECTOR_LENGTH = 4; + uint256 private constant REPORT_LENGTH = 64; + struct HotVars { bool reentrancyGuard; // guard against reentrancy } @@ -26,7 +34,9 @@ contract KeystoneForwarder is IForwarder, ConfirmedOwner, TypeAndVersionInterfac bytes calldata data, bytes[] calldata signatures ) external nonReentrant returns (bool) { - require(data.length > 4 + 64, "invalid data length"); + if (data.length < SELECTOR_LENGTH + REPORT_LENGTH) { + revert InvalidData(data); + } // data is an encoded call with the selector prefixed: (bytes4 selector, bytes report, ...) // we are able to partially decode just the first param, since we don't know the rest diff --git a/contracts/src/v0.8/keystone/test/CapabilityRegistry.t.sol b/contracts/src/v0.8/keystone/test/CapabilityRegistry.t.sol new file mode 100644 index 00000000000..f5d539d8e34 --- /dev/null +++ b/contracts/src/v0.8/keystone/test/CapabilityRegistry.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {Test} from "forge-std/Test.sol"; +import {Capability, CapabilityRegistry} from "../CapabilityRegistry.sol"; + +contract CapabilityRegistryTest is Test { + function setUp() public virtual {} + + function testAddCapability() public { + CapabilityRegistry capabilityRegistry = new CapabilityRegistry(); + + capabilityRegistry.addCapability(Capability("data-streams-reports", "1.0.0")); + + bytes32 capabilityId = capabilityRegistry.getCapabilityID(bytes32("data-streams-reports"), bytes32("1.0.0")); + Capability memory capability = capabilityRegistry.getCapability(capabilityId); + + assertEq(capability.capabilityType, "data-streams-reports"); + assertEq(capability.version, "1.0.0"); + } +} diff --git a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index 77c225cdb02..1d741280851 100644 --- a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -32,6 +32,27 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume LinkTokenInterface internal immutable i_link; AggregatorV3Interface internal immutable i_link_native_feed; + event FulfillmentTxSizeSet(uint32 size); + event ConfigSet( + uint32 wrapperGasOverhead, + uint32 coordinatorGasOverheadNative, + uint32 coordinatorGasOverheadLink, + uint16 coordinatorGasOverheadPerWord, + uint8 coordinatorNativePremiumPercentage, + uint8 coordinatorLinkPremiumPercentage, + bytes32 keyHash, + uint8 maxNumWords, + uint32 stalenessSeconds, + int256 fallbackWeiPerUnitLink, + uint32 fulfillmentFlatFeeNativePPM, + uint32 fulfillmentFlatFeeLinkDiscountPPM + ); + event FallbackWeiPerUnitLinkUsed(uint256 requestId, int256 fallbackWeiPerUnitLink); + event Withdrawn(address indexed to, uint256 amount); + event NativeWithdrawn(address indexed to, uint256 amount); + event Enabled(); + event Disabled(); + error LinkAlreadySet(); error LinkDiscountTooHigh(uint32 flatFeeLinkDiscountPPM, uint32 flatFeeNativePPM); error InvalidPremiumPercentage(uint8 premiumPercentage, uint8 max); @@ -95,11 +116,18 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume /// @dev total data size = 4608 bits + 32 bits = 4640 bits = 580 bytes uint32 public s_fulfillmentTxSizeBytes = 580; - // s_coordinatorGasOverhead reflects the gas overhead of the coordinator's fulfillRandomWords - // function. The cost for this gas is billed to the subscription, and must therefor be included + // s_coordinatorGasOverheadNative reflects the gas overhead of the coordinator's fulfillRandomWords + // function for native payment. The cost for this gas is billed to the subscription, and must therefor be included + // in the pricing for wrapped requests. This includes the gas costs of proof verification and + // payment calculation in the coordinator. + uint32 private s_coordinatorGasOverheadNative; + + // s_coordinatorGasOverheadLink reflects the gas overhead of the coordinator's fulfillRandomWords + // function for link payment. The cost for this gas is billed to the subscription, and must therefor be included // in the pricing for wrapped requests. This includes the gas costs of proof verification and // payment calculation in the coordinator. - uint32 private s_coordinatorGasOverhead; + uint32 private s_coordinatorGasOverheadLink; + uint16 private s_coordinatorGasOverheadPerWord; // s_fulfillmentFlatFeeLinkPPM is the flat fee in millionths of native that VRFCoordinatorV2 @@ -119,8 +147,6 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // value of 0 indicates no premium. A value of 15 indicates a 15 percent premium. // Wrapper has no premium. This premium is for VRFCoordinator. uint8 private s_coordinatorLinkPremiumPercentage; - - // 4 bytes left /* Storage Slot 5: END */ struct Callback { @@ -179,7 +205,13 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords * function. * - * @param _coordinatorGasOverhead reflects the gas overhead of the coordinator's + * @param _coordinatorGasOverheadNative reflects the gas overhead of the coordinator's + * fulfillRandomWords function for native payment. + * + * @param _coordinatorGasOverheadLink reflects the gas overhead of the coordinator's + * fulfillRandomWords function for link payment. + * + * @param _coordinatorGasOverheadPerWord reflects the gas overhead per word of the coordinator's * fulfillRandomWords function. * * @param _coordinatorNativePremiumPercentage is the coordinator's premium ratio in percentage for requests paid in native. @@ -202,7 +234,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume */ function setConfig( uint32 _wrapperGasOverhead, - uint32 _coordinatorGasOverhead, + uint32 _coordinatorGasOverheadNative, + uint32 _coordinatorGasOverheadLink, uint16 _coordinatorGasOverheadPerWord, uint8 _coordinatorNativePremiumPercentage, uint8 _coordinatorLinkPremiumPercentage, @@ -224,7 +257,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume } s_wrapperGasOverhead = _wrapperGasOverhead; - s_coordinatorGasOverhead = _coordinatorGasOverhead; + s_coordinatorGasOverheadNative = _coordinatorGasOverheadNative; + s_coordinatorGasOverheadLink = _coordinatorGasOverheadLink; s_coordinatorGasOverheadPerWord = _coordinatorGasOverheadPerWord; s_coordinatorNativePremiumPercentage = _coordinatorNativePremiumPercentage; s_coordinatorLinkPremiumPercentage = _coordinatorLinkPremiumPercentage; @@ -240,7 +274,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume emit ConfigSet( _wrapperGasOverhead, - _coordinatorGasOverhead, + _coordinatorGasOverheadNative, + _coordinatorGasOverheadLink, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, @@ -271,8 +306,11 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @return wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords * function. The cost for this gas is passed to the user. * - * @return coordinatorGasOverhead reflects the gas overhead of the coordinator's - * fulfillRandomWords function. + * @return coordinatorGasOverheadNative reflects the gas overhead of the coordinator's + * fulfillRandomWords function for native payment. + * + * @return coordinatorGasOverheadLink reflects the gas overhead of the coordinator's + * fulfillRandomWords function for link payment. * * @return coordinatorGasOverheadPerWord reflects the gas overhead per word of the coordinator's * fulfillRandomWords function. @@ -298,7 +336,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume uint32 fulfillmentFlatFeeNativePPM, uint32 fulfillmentFlatFeeLinkDiscountPPM, uint32 wrapperGasOverhead, - uint32 coordinatorGasOverhead, + uint32 coordinatorGasOverheadNative, + uint32 coordinatorGasOverheadLink, uint16 coordinatorGasOverheadPerWord, uint8 wrapperNativePremiumPercentage, uint8 wrapperLinkPremiumPercentage, @@ -312,7 +351,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume s_fulfillmentFlatFeeNativePPM, s_fulfillmentFlatFeeLinkDiscountPPM, s_wrapperGasOverhead, - s_coordinatorGasOverhead, + s_coordinatorGasOverheadNative, + s_coordinatorGasOverheadLink, s_coordinatorGasOverheadPerWord, s_coordinatorNativePremiumPercentage, s_coordinatorLinkPremiumPercentage, @@ -383,7 +423,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2. // (wei/gas) * gas + l1wei uint256 coordinatorCostWei = _requestGasPrice * - (_gas + _getCoordinatorGasOverhead(_numWords)) + + (_gas + _getCoordinatorGasOverhead(_numWords, true)) + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes); // coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied @@ -407,7 +447,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2. // (wei/gas) * gas + l1wei uint256 coordinatorCostWei = _requestGasPrice * - (_gas + _getCoordinatorGasOverhead(_numWords)) + + (_gas + _getCoordinatorGasOverhead(_numWords, false)) + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes); // coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied @@ -621,8 +661,12 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume return gas / 63 + 1; } - function _getCoordinatorGasOverhead(uint32 numWords) internal view returns (uint32) { - return s_coordinatorGasOverhead + numWords * s_coordinatorGasOverheadPerWord; + function _getCoordinatorGasOverhead(uint32 numWords, bool nativePayment) internal view returns (uint32) { + if (nativePayment) { + return s_coordinatorGasOverheadNative + numWords * s_coordinatorGasOverheadPerWord; + } else { + return s_coordinatorGasOverheadLink + numWords * s_coordinatorGasOverheadPerWord; + } } /** diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol index 917c59433ef..85b0c47659d 100644 --- a/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol @@ -2,26 +2,6 @@ pragma solidity ^0.8.0; interface IVRFV2PlusWrapper { - event FulfillmentTxSizeSet(uint32 size); - event ConfigSet( - uint32 wrapperGasOverhead, - uint32 coordinatorGasOverhead, - uint16 coordinatorGasOverheadPerWord, - uint8 coordinatorNativePremiumPercentage, - uint8 coordinatorLinkPremiumPercentage, - bytes32 keyHash, - uint8 maxNumWords, - uint32 stalenessSeconds, - int256 fallbackWeiPerUnitLink, - uint32 fulfillmentFlatFeeNativePPM, - uint32 fulfillmentFlatFeeLinkDiscountPPM - ); - event FallbackWeiPerUnitLinkUsed(uint256 requestId, int256 fallbackWeiPerUnitLink); - event Withdrawn(address indexed to, uint256 amount); - event NativeWithdrawn(address indexed to, uint256 amount); - event Enabled(); - event Disabled(); - /** * @return the request ID of the most recent VRF V2 request made by this wrapper. This should only * be relied option within the same transaction that the request was made. diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index 6599a68a96e..c88d7dec397 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -5,6 +5,7 @@ import {BlockhashStoreInterface} from "../../interfaces/BlockhashStoreInterface. // solhint-disable-next-line no-unused-import import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; import {VRF} from "../../../vrf/VRF.sol"; +import {VRFTypes} from "../../VRFTypes.sol"; import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "../VRFConsumerBaseV2Plus.sol"; import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; import {SubscriptionAPI} from "../SubscriptionAPI.sol"; @@ -30,37 +31,39 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100) // and some arithmetic operations. uint256 private constant GAS_FOR_CALL_EXACT_CHECK = 5_000; + // upper bound limit for premium percentages to make sure fee calculations don't overflow + uint8 private constant PREMIUM_PERCENTAGE_MAX = 155; error InvalidRequestConfirmations(uint16 have, uint16 min, uint16 max); error GasLimitTooBig(uint32 have, uint32 want); error NumWordsTooBig(uint32 have, uint32 want); + error MsgDataTooBig(uint256 have, uint32 max); error ProvingKeyAlreadyRegistered(bytes32 keyHash); error NoSuchProvingKey(bytes32 keyHash); error InvalidLinkWeiPrice(int256 linkWei); + error LinkDiscountTooHigh(uint32 flatFeeLinkDiscountPPM, uint32 flatFeeNativePPM); + error InvalidPremiumPercentage(uint8 premiumPercentage, uint8 max); error NoCorrespondingRequest(); error IncorrectCommitment(); error BlockhashNotInStore(uint256 blockNum); error PaymentTooLarge(); error InvalidExtraArgsTag(); + error GasPriceExceeded(uint256 gasPrice, uint256 maxGas); /// @notice emitted when version in the request doesn't match expected version error InvalidVersion(uint8 requestVersion, uint8 expectedVersion); /// @notice emitted when transferred balance (msg.value) does not match the metadata in V1MigrationData error InvalidNativeBalance(uint256 transferredValue, uint96 expectedValue); error SubscriptionIDCollisionFound(); - struct RequestCommitment { - uint64 blockNum; - uint256 subId; - uint32 callbackGasLimit; - uint32 numWords; - address sender; - bytes extraArgs; + struct ProvingKey { + bool exists; // proving key exists + uint64 maxGas; // gas lane max gas price for fulfilling requests } - mapping(bytes32 => bool) /* keyHash */ /* exists */ internal s_provingKeys; + mapping(bytes32 => ProvingKey) /* keyHash */ /* provingKey */ public s_provingKeys; bytes32[] public s_provingKeyHashes; mapping(uint256 => bytes32) /* requestID */ /* commitment */ public s_requestCommitments; + event ProvingKeyRegistered(bytes32 keyHash, uint64 maxGas); - event ProvingKeyRegistered(bytes32 keyHash); event RandomWordsRequested( bytes32 indexed keyHash, uint256 requestId, @@ -72,26 +75,18 @@ contract VRFCoordinatorV2PlusUpgradedVersion is bytes extraArgs, address indexed sender ); + event RandomWordsFulfilled( uint256 indexed requestId, uint256 outputSeed, - uint256 indexed subID, + uint256 indexed subId, uint96 payment, - bool success + bool nativePayment, + bool success, + bool onlyPremium ); - int256 internal s_fallbackWeiPerUnitLink; - - FeeConfig internal s_feeConfig; - - struct FeeConfig { - // Flat fee charged per fulfillment in millionths of link - // So fee range is [0, 2^32/10^6]. - uint32 fulfillmentFlatFeeLinkPPM; - // Flat fee charged per fulfillment in millionths of native. - // So fee range is [0, 2^32/10^6]. - uint32 fulfillmentFlatFeeNativePPM; - } + int256 public s_fallbackWeiPerUnitLink; event ConfigSet( uint16 minimumRequestConfirmations, @@ -99,26 +94,30 @@ contract VRFCoordinatorV2PlusUpgradedVersion is uint32 stalenessSeconds, uint32 gasAfterPaymentCalculation, int256 fallbackWeiPerUnitLink, + uint32 fulfillmentFlatFeeNativePPM, + uint32 fulfillmentFlatFeeLinkDiscountPPM, uint8 nativePremiumPercentage, uint8 linkPremiumPercentage ); + event FallbackWeiPerUnitLinkUsed(uint256 requestId, int256 fallbackWeiPerUnitLink); + constructor(address blockhashStore) SubscriptionAPI() { BLOCKHASH_STORE = BlockhashStoreInterface(blockhashStore); } /** - * @notice Registers a proving key to an oracle. + * @notice Registers a proving key to. * @param publicProvingKey key that oracle can use to submit vrf fulfillments */ - function registerProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { + function registerProvingKey(uint256[2] calldata publicProvingKey, uint64 maxGas) external onlyOwner { bytes32 kh = hashOfKey(publicProvingKey); - if (s_provingKeys[kh]) { + if (s_provingKeys[kh].exists) { revert ProvingKeyAlreadyRegistered(kh); } - s_provingKeys[kh] = true; + s_provingKeys[kh] = ProvingKey({exists: true, maxGas: maxGas}); s_provingKeyHashes.push(kh); - emit ProvingKeyRegistered(kh); + emit ProvingKeyRegistered(kh, maxGas); } /** @@ -136,6 +135,8 @@ contract VRFCoordinatorV2PlusUpgradedVersion is * @param stalenessSeconds if the native/link feed is more stale then this, use the fallback price * @param gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement * @param fallbackWeiPerUnitLink fallback native/link price in the case of a stale feed + * @param fulfillmentFlatFeeNativePPM flat fee in native for native payment + * @param fulfillmentFlatFeeLinkDiscountPPM flat fee discount for link payment in native * @param nativePremiumPercentage native premium percentage * @param linkPremiumPercentage link premium percentage */ @@ -160,6 +161,15 @@ contract VRFCoordinatorV2PlusUpgradedVersion is if (fallbackWeiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); } + if (fulfillmentFlatFeeLinkDiscountPPM > fulfillmentFlatFeeNativePPM) { + revert LinkDiscountTooHigh(fulfillmentFlatFeeLinkDiscountPPM, fulfillmentFlatFeeNativePPM); + } + if (nativePremiumPercentage > PREMIUM_PERCENTAGE_MAX) { + revert InvalidPremiumPercentage(nativePremiumPercentage, PREMIUM_PERCENTAGE_MAX); + } + if (linkPremiumPercentage > PREMIUM_PERCENTAGE_MAX) { + revert InvalidPremiumPercentage(linkPremiumPercentage, PREMIUM_PERCENTAGE_MAX); + } s_config = Config({ minimumRequestConfirmations: minimumRequestConfirmations, maxGasLimit: maxGasLimit, @@ -178,6 +188,8 @@ contract VRFCoordinatorV2PlusUpgradedVersion is stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, + fulfillmentFlatFeeNativePPM, + fulfillmentFlatFeeLinkDiscountPPM, nativePremiumPercentage, linkPremiumPercentage ); @@ -232,18 +244,18 @@ contract VRFCoordinatorV2PlusUpgradedVersion is */ function requestRandomWords( VRFV2PlusClient.RandomWordsRequest calldata req - ) external override nonReentrant returns (uint256) { + ) external override nonReentrant returns (uint256 requestId) { // Input validation using the subscription storage. - if (s_subscriptionConfigs[req.subId].owner == address(0)) { + uint256 subId = req.subId; + if (s_subscriptionConfigs[subId].owner == address(0)) { revert InvalidSubscription(); } // Its important to ensure that the consumer is in fact who they say they // are, otherwise they could use someone else's subscription balance. - // A nonce of 0 indicates consumer is not allocated to the sub. mapping(uint256 => ConsumerConfig) storage consumerConfigs = s_consumers[msg.sender]; - ConsumerConfig memory consumerConfig = consumerConfigs[req.subId]; + ConsumerConfig memory consumerConfig = consumerConfigs[subId]; if (!consumerConfig.active) { - revert InvalidConsumer(req.subId, msg.sender); + revert InvalidConsumer(subId, msg.sender); } // Input validation using the config storage word. if ( @@ -265,19 +277,21 @@ contract VRFCoordinatorV2PlusUpgradedVersion is if (req.numWords > MAX_NUM_WORDS) { revert NumWordsTooBig(req.numWords, MAX_NUM_WORDS); } + // Note we do not check whether the keyHash is valid to save gas. // The consequence for users is that they can send requests // for invalid keyHashes which will simply not be fulfilled. ++consumerConfig.nonce; - (uint256 requestId, uint256 preSeed) = _computeRequestId(req.keyHash, msg.sender, req.subId, consumerConfig.nonce); + ++consumerConfig.pendingReqCount; + uint256 preSeed; + (requestId, preSeed) = _computeRequestId(req.keyHash, msg.sender, subId, consumerConfig.nonce); - VRFV2PlusClient.ExtraArgsV1 memory extraArgs = _fromBytes(req.extraArgs); - bytes memory extraArgsBytes = VRFV2PlusClient._argsToBytes(extraArgs); + bytes memory extraArgsBytes = VRFV2PlusClient._argsToBytes(_fromBytes(req.extraArgs)); s_requestCommitments[requestId] = keccak256( abi.encode( requestId, ChainSpecificUtil._getBlockNumber(), - req.subId, + subId, req.callbackGasLimit, req.numWords, msg.sender, @@ -288,14 +302,14 @@ contract VRFCoordinatorV2PlusUpgradedVersion is req.keyHash, requestId, preSeed, - req.subId, + subId, req.requestConfirmations, req.callbackGasLimit, req.numWords, extraArgsBytes, msg.sender ); - s_consumers[msg.sender][req.subId] = consumerConfig; + consumerConfigs[subId] = consumerConfig; return requestId; } @@ -344,18 +358,19 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } struct Output { - bytes32 keyHash; + ProvingKey provingKey; uint256 requestId; uint256 randomness; } function _getRandomnessFromProof( Proof memory proof, - RequestCommitment memory rc + VRFTypes.RequestCommitmentV2Plus memory rc ) internal view returns (Output memory) { bytes32 keyHash = hashOfKey(proof.pk); + ProvingKey memory key = s_provingKeys[keyHash]; // Only registered proving keys are permitted. - if (!s_provingKeys[keyHash]) { + if (!key.exists) { revert NoSuchProvingKey(keyHash); } uint256 requestId = uint256(keccak256(abi.encode(keyHash, proof.seed))); @@ -381,179 +396,232 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); uint256 randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure - return Output(keyHash, requestId, randomness); + return Output(key, requestId, randomness); + } + + function _getValidatedGasPrice(bool onlyPremium, uint64 gasLaneMaxGas) internal view returns (uint256 gasPrice) { + if (tx.gasprice > gasLaneMaxGas) { + if (onlyPremium) { + // if only the premium amount needs to be billed, then the premium is capped by the gas lane max + return uint256(gasLaneMaxGas); + } else { + // Ensure gas price does not exceed the gas lane max gas price + revert GasPriceExceeded(tx.gasprice, gasLaneMaxGas); + } + } + return tx.gasprice; + } + + function _deliverRandomness( + uint256 requestId, + VRFTypes.RequestCommitmentV2Plus memory rc, + uint256[] memory randomWords + ) internal returns (bool success) { + VRFConsumerBaseV2Plus v; + bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomWords.selector, requestId, randomWords); + // Call with explicitly the amount of callback gas requested + // Important to not let them exhaust the gas budget and avoid oracle payment. + // Do not allow any non-view/non-pure coordinator functions to be called + // during the consumers callback code via reentrancyLock. + // Note that _callWithExactGas will revert if we do not have sufficient gas + // to give the callee their requested amount. + s_config.reentrancyLock = true; + success = _callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + s_config.reentrancyLock = false; + return success; } /* - * @notice Fulfill a randomness request + * @notice Fulfill a randomness request. * @param proof contains the proof and randomness * @param rc request commitment pre-image, committed to at request time + * @param onlyPremium only charge premium * @return payment amount billed to the subscription * @dev simulated offchain to determine if sufficient balance is present to fulfill the request */ function fulfillRandomWords( Proof memory proof, - RequestCommitment memory rc, - bool - ) external nonReentrant returns (uint96) { + VRFTypes.RequestCommitmentV2Plus memory rc, + bool onlyPremium + ) external nonReentrant returns (uint96 payment) { uint256 startGas = gasleft(); + // fulfillRandomWords msg.data has 772 bytes and with an additional + // buffer of 32 bytes, we get 804 bytes. + /* Data size split: + * fulfillRandomWords function signature - 4 bytes + * proof - 416 bytes + * pk - 64 bytes + * gamma - 64 bytes + * c - 32 bytes + * s - 32 bytes + * seed - 32 bytes + * uWitness - 32 bytes + * cGammaWitness - 64 bytes + * sHashWitness - 64 bytes + * zInv - 32 bytes + * requestCommitment - 320 bytes + * blockNum - 32 bytes + * subId - 32 bytes + * callbackGasLimit - 32 bytes + * numWords - 32 bytes + * sender - 32 bytes + * extraArgs - 128 bytes + * onlyPremium - 32 bytes + */ + if (msg.data.length > 804) { + revert MsgDataTooBig(msg.data.length, 804); + } Output memory output = _getRandomnessFromProof(proof, rc); + uint256 gasPrice = _getValidatedGasPrice(onlyPremium, output.provingKey.maxGas); - uint256[] memory randomWords = new uint256[](rc.numWords); - for (uint256 i = 0; i < rc.numWords; i++) { - randomWords[i] = uint256(keccak256(abi.encode(output.randomness, i))); + uint256[] memory randomWords; + uint256 randomness = output.randomness; + // stack too deep error + { + uint256 numWords = rc.numWords; + randomWords = new uint256[](numWords); + for (uint256 i = 0; i < numWords; ++i) { + randomWords[i] = uint256(keccak256(abi.encode(randomness, i))); + } } delete s_requestCommitments[output.requestId]; - VRFConsumerBaseV2Plus v; - bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomWords.selector, output.requestId, randomWords); - // Call with explicitly the amount of callback gas requested - // Important to not let them exhaust the gas budget and avoid oracle payment. - // Do not allow any non-view/non-pure coordinator functions to be called - // during the consumers callback code via reentrancyLock. - // Note that _callWithExactGas will revert if we do not have sufficient gas - // to give the callee their requested amount. - s_config.reentrancyLock = true; - bool success = _callWithExactGas(rc.callbackGasLimit, rc.sender, resp); - s_config.reentrancyLock = false; + bool success = _deliverRandomness(output.requestId, rc, randomWords); // Increment the req count for the subscription. - uint64 reqCount = s_subscriptions[rc.subId].reqCount; - s_subscriptions[rc.subId].reqCount = reqCount + 1; + ++s_subscriptions[rc.subId].reqCount; + // Decrement the pending req count for the consumer. + --s_consumers[rc.sender][rc.subId].pendingReqCount; + + bool nativePayment = uint8(rc.extraArgs[rc.extraArgs.length - 1]) == 1; // stack too deep error { - bool nativePayment = uint8(rc.extraArgs[rc.extraArgs.length - 1]) == 1; - // We want to charge users exactly for how much gas they use in their callback. - // The gasAfterPaymentCalculation is meant to cover these additional operations where we - // decrement the subscription balance and increment the oracles withdrawable balance. - uint96 payment = _calculatePaymentAmount( - startGas, - s_config.gasAfterPaymentCalculation, - tx.gasprice, - nativePayment - ); - if (nativePayment) { - if (s_subscriptions[rc.subId].nativeBalance < payment) { - revert InsufficientBalance(); - } - s_subscriptions[rc.subId].nativeBalance -= payment; - s_withdrawableNative += payment; - } else { - if (s_subscriptions[rc.subId].balance < payment) { - revert InsufficientBalance(); - } - s_subscriptions[rc.subId].balance -= payment; - s_withdrawableTokens += payment; + // We want to charge users exactly for how much gas they use in their callback with + // an additional premium. If onlyPremium is true, only premium is charged without + // the gas cost. The gasAfterPaymentCalculation is meant to cover these additional + // operations where we decrement the subscription balance and increment the + // withdrawable balance. + bool isFeedStale; + (payment, isFeedStale) = _calculatePaymentAmount(startGas, gasPrice, nativePayment, onlyPremium); + if (isFeedStale) { + emit FallbackWeiPerUnitLinkUsed(output.requestId, s_fallbackWeiPerUnitLink); } + } + + _chargePayment(payment, nativePayment, rc.subId); - // Include payment in the event for tracking costs. - // event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bytes extraArgs, bool success); - emit RandomWordsFulfilled(output.requestId, output.randomness, rc.subId, payment, success); + // Include payment in the event for tracking costs. + emit RandomWordsFulfilled(output.requestId, randomness, rc.subId, payment, nativePayment, success, onlyPremium); + + return payment; + } - return payment; + function _chargePayment(uint96 payment, bool nativePayment, uint256 subId) internal { + Subscription storage subcription = s_subscriptions[subId]; + if (nativePayment) { + uint96 prevBal = subcription.nativeBalance; + if (prevBal < payment) { + revert InsufficientBalance(); + } + subcription.nativeBalance = prevBal - payment; + s_withdrawableNative += payment; + } else { + uint96 prevBal = subcription.balance; + if (prevBal < payment) { + revert InsufficientBalance(); + } + subcription.balance = prevBal - payment; + s_withdrawableTokens += payment; } } function _calculatePaymentAmount( uint256 startGas, - uint256 gasAfterPaymentCalculation, uint256 weiPerUnitGas, - bool nativePayment - ) internal view returns (uint96) { + bool nativePayment, + bool onlyPremium + ) internal view returns (uint96, bool) { if (nativePayment) { - return - _calculatePaymentAmountNative( - startGas, - gasAfterPaymentCalculation, - s_feeConfig.fulfillmentFlatFeeNativePPM, - weiPerUnitGas - ); - } - return - _calculatePaymentAmountLink( - startGas, - gasAfterPaymentCalculation, - s_feeConfig.fulfillmentFlatFeeLinkPPM, - weiPerUnitGas - ); + return (_calculatePaymentAmountNative(startGas, weiPerUnitGas, onlyPremium), false); + } + return _calculatePaymentAmountLink(startGas, weiPerUnitGas, onlyPremium); } function _calculatePaymentAmountNative( uint256 startGas, - uint256 gasAfterPaymentCalculation, - uint32 fulfillmentFlatFeePPM, - uint256 weiPerUnitGas + uint256 weiPerUnitGas, + bool onlyPremium ) internal view returns (uint96) { // Will return non-zero on chains that have this enabled uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // calculate the payment without the premium - uint256 baseFeeWei = weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()); - // calculate the flat fee in wei - uint256 flatFeeWei = 1e12 * uint256(fulfillmentFlatFeePPM); - // return the final fee with the flat fee and l1 cost (if applicable) added - return uint96(baseFeeWei + flatFeeWei + l1CostWei); + uint256 baseFeeWei = weiPerUnitGas * (s_config.gasAfterPaymentCalculation + startGas - gasleft()); + // calculate flat fee in native + uint256 flatFeeWei = 1e12 * uint256(s_config.fulfillmentFlatFeeNativePPM); + if (onlyPremium) { + return uint96((((l1CostWei + baseFeeWei) * (s_config.nativePremiumPercentage)) / 100) + flatFeeWei); + } else { + return uint96((((l1CostWei + baseFeeWei) * (100 + s_config.nativePremiumPercentage)) / 100) + flatFeeWei); + } } // Get the amount of gas used for fulfillment function _calculatePaymentAmountLink( uint256 startGas, - uint256 gasAfterPaymentCalculation, - uint32 fulfillmentFlatFeeLinkPPM, - uint256 weiPerUnitGas - ) internal view returns (uint96) { - int256 weiPerUnitLink; - weiPerUnitLink = _getFeedData(); + uint256 weiPerUnitGas, + bool onlyPremium + ) internal view returns (uint96, bool) { + (int256 weiPerUnitLink, bool isFeedStale) = _getFeedData(); if (weiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / + uint256 paymentNoFee = (1e18 * + (weiPerUnitGas * (s_config.gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); - uint256 fee = 1e12 * uint256(fulfillmentFlatFeeLinkPPM); - if (paymentNoFee > (1e27 - fee)) { + // calculate the flat fee in wei + uint256 flatFeeWei = 1e12 * + uint256(s_config.fulfillmentFlatFeeNativePPM - s_config.fulfillmentFlatFeeLinkDiscountPPM); + uint256 flatFeeJuels = (1e18 * flatFeeWei) / uint256(weiPerUnitLink); + uint256 payment; + if (onlyPremium) { + payment = ((paymentNoFee * (s_config.linkPremiumPercentage)) / 100 + flatFeeJuels); + } else { + payment = ((paymentNoFee * (100 + s_config.linkPremiumPercentage)) / 100 + flatFeeJuels); + } + if (payment > 1e27) { revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. } - return uint96(paymentNoFee + fee); + return (uint96(payment), isFeedStale); } - function _getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256 weiPerUnitLink, bool isFeedStale) { uint32 stalenessSeconds = s_config.stalenessSeconds; - bool staleFallback = stalenessSeconds > 0; uint256 timestamp; - int256 weiPerUnitLink; (, weiPerUnitLink, , timestamp, ) = LINK_NATIVE_FEED.latestRoundData(); // solhint-disable-next-line not-rely-on-time - if (staleFallback && stalenessSeconds < block.timestamp - timestamp) { + isFeedStale = stalenessSeconds > 0 && stalenessSeconds < block.timestamp - timestamp; + if (isFeedStale) { weiPerUnitLink = s_fallbackWeiPerUnitLink; } - return weiPerUnitLink; + return (weiPerUnitLink, isFeedStale); } - /* - * @notice Check to see if there exists a request commitment consumers - * for all consumers and keyhashes for a given sub. - * @param subId - ID of the subscription - * @return true if there exists at least one unfulfilled request for the subscription, false - * otherwise. - * @dev Looping is bounded to MAX_CONSUMERS*(number of keyhashes). - * @dev Used to disable subscription canceling while outstanding request are present. + /** + * @inheritdoc IVRFSubscriptionV2Plus */ function pendingRequestExists(uint256 subId) public view override returns (bool) { - SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; - for (uint256 i = 0; i < subConfig.consumers.length; i++) { - for (uint256 j = 0; j < s_provingKeyHashes.length; j++) { - (uint256 reqId, ) = _computeRequestId( - s_provingKeyHashes[j], - subConfig.consumers[i], - subId, - s_consumers[subConfig.consumers[i]][subId].nonce - ); - if (s_requestCommitments[reqId] != 0) { - return true; - } + address[] storage consumers = s_subscriptionConfigs[subId].consumers; + uint256 consumersLength = consumers.length; + if (consumersLength == 0) { + return false; + } + for (uint256 i = 0; i < consumersLength; ++i) { + if (s_consumers[consumers[i]][subId].pendingReqCount > 0) { + return true; } } return false; @@ -572,7 +640,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // Note bounded by MAX_CONSUMERS address[] memory consumers = s_subscriptionConfigs[subId].consumers; uint256 lastConsumerIndex = consumers.length - 1; - for (uint256 i = 0; i < consumers.length; i++) { + for (uint256 i = 0; i < consumers.length; ++i) { if (consumers[i] == consumer) { address last = consumers[lastConsumerIndex]; // Storage write to preserve last element @@ -582,7 +650,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is break; } } - delete s_consumers[consumer][subId]; + s_consumers[consumer][subId].active = false; emit SubscriptionConsumerRemoved(subId, consumer); } @@ -627,7 +695,8 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } function _isTargetRegistered(address target) internal view returns (bool) { - for (uint256 i = 0; i < s_migrationTargets.length; i++) { + uint256 migrationTargetsLength = s_migrationTargets.length; + for (uint256 i = 0; i < migrationTargetsLength; ++i) { if (s_migrationTargets[i] == target) { return true; } @@ -647,16 +716,16 @@ contract VRFCoordinatorV2PlusUpgradedVersion is if (!_isTargetRegistered(newCoordinator)) { revert CoordinatorNotRegistered(newCoordinator); } - (uint96 balance, uint96 nativeBalance, , address owner, address[] memory consumers) = getSubscription(subId); + (uint96 balance, uint96 nativeBalance, , address subOwner, address[] memory consumers) = getSubscription(subId); // solhint-disable-next-line gas-custom-errors - require(owner == msg.sender, "Not subscription owner"); + require(subOwner == msg.sender, "Not subscription owner"); // solhint-disable-next-line gas-custom-errors require(!pendingRequestExists(subId), "Pending request exists"); V1MigrationData memory migrationData = V1MigrationData({ - fromVersion: migrationVersion(), + fromVersion: 1, subId: subId, - subOwner: owner, + subOwner: subOwner, consumers: consumers, linkBalance: balance, nativeBalance: nativeBalance @@ -674,7 +743,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // despite the fact that we follow best practices this is still probably safest // to prevent any re-entrancy possibilities. s_config.reentrancyLock = true; - for (uint256 i = 0; i < consumers.length; i++) { + for (uint256 i = 0; i < consumers.length; ++i) { IVRFMigratableConsumerV2Plus(consumers[i]).setCoordinator(newCoordinator); } s_config.reentrancyLock = false; diff --git a/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol index 66bef8a1bcd..4b3a893fe1f 100644 --- a/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol @@ -16,7 +16,8 @@ contract VRFV2PlusWrapperTest is BaseTest { address internal constant LINK_WHALE = 0xD883a6A1C22fC4AbFE938a5aDF9B2Cc31b1BF18B; bytes32 private vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; uint32 private wrapperGasOverhead = 100_000; - uint32 private coordinatorGasOverhead = 200_000; + uint32 private coordinatorGasOverheadNative = 200_000; + uint32 private coordinatorGasOverheadLink = 220_000; uint256 private s_wrapperSubscriptionId; ExposedVRFCoordinatorV2_5 private s_testCoordinator; @@ -84,10 +85,24 @@ contract VRFV2PlusWrapperTest is BaseTest { function setConfigWrapper() internal { vm.expectEmit(false, false, false, true, address(s_wrapper)); - emit ConfigSet(wrapperGasOverhead, coordinatorGasOverhead, 0, 0, 0, vrfKeyHash, 10, 1, 50000000000000000, 0, 0); + emit ConfigSet( + wrapperGasOverhead, + coordinatorGasOverheadNative, + coordinatorGasOverheadLink, + 0, + 0, + 0, + vrfKeyHash, + 10, + 1, + 50000000000000000, + 0, + 0 + ); s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 0, // native premium percentage, 0, // link premium percentage @@ -104,7 +119,8 @@ contract VRFV2PlusWrapperTest is BaseTest { , , uint32 _wrapperGasOverhead, - uint32 _coordinatorGasOverhead, + uint32 _coordinatorGasOverheadNative, + uint32 _coordinatorGasOverheadLink, uint16 _coordinatorGasOverheadPerWord, uint8 _coordinatorNativePremiumPercentage, uint8 _coordinatorLinkPremiumPercentage, @@ -112,7 +128,8 @@ contract VRFV2PlusWrapperTest is BaseTest { uint8 _maxNumWords ) = s_wrapper.getConfig(); assertEq(_wrapperGasOverhead, wrapperGasOverhead); - assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); + assertEq(_coordinatorGasOverheadNative, coordinatorGasOverheadNative); + assertEq(_coordinatorGasOverheadLink, coordinatorGasOverheadLink); assertEq(0, _coordinatorGasOverheadPerWord); assertEq(0, _coordinatorNativePremiumPercentage); assertEq(0, _coordinatorLinkPremiumPercentage); @@ -137,7 +154,8 @@ contract VRFV2PlusWrapperTest is BaseTest { event FulfillmentTxSizeSet(uint32 size); event ConfigSet( uint32 wrapperGasOverhead, - uint32 coordinatorGasOverhead, + uint32 coordinatorGasOverheadNative, + uint32 coordinatorGasOverheadLink, uint16 coordinatorGasOverheadPerWord, uint8 coordinatorNativePremiumPercentage, uint8 coordinatorLinkPremiumPercentage, @@ -241,7 +259,7 @@ contract VRFV2PlusWrapperTest is BaseTest { requestId = s_consumer.makeRequestNative(callbackGasLimit, 0, 1); (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); - uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead; + uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverheadNative; uint256 wrapperNativeCostEstimate = s_wrapper.estimateRequestPriceNative(callbackGasLimit, 0, tx.gasprice); uint256 wrapperCostCalculation = s_wrapper.calculateRequestPriceNative(callbackGasLimit, 0); assertEq(paid, expectedPaid); @@ -277,7 +295,8 @@ contract VRFV2PlusWrapperTest is BaseTest { vm.expectRevert(abi.encodeWithSelector(VRFV2PlusWrapper.LinkDiscountTooHigh.selector, uint32(501), uint32(500))); s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 0, // native premium percentage, 0, // link premium percentage @@ -294,7 +313,8 @@ contract VRFV2PlusWrapperTest is BaseTest { // Test that setting link discount flat fee equal to native flat fee does not revert s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 0, // native premium percentage, 0, // link premium percentage @@ -314,7 +334,8 @@ contract VRFV2PlusWrapperTest is BaseTest { ); s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 156, // native premium percentage, 0, // link premium percentage @@ -334,7 +355,8 @@ contract VRFV2PlusWrapperTest is BaseTest { ); s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 15, // native premium percentage, 202, // link premium percentage @@ -377,7 +399,7 @@ contract VRFV2PlusWrapperTest is BaseTest { // Assert that the request was made correctly. (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); - uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead) * 2; + uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverheadLink) * 2; uint256 wrapperCostEstimate = s_wrapper.estimateRequestPrice(callbackGasLimit, 0, tx.gasprice); uint256 wrapperCostCalculation = s_wrapper.calculateRequestPrice(callbackGasLimit, 0); assertEq(paid, expectedPaid); // 1_030_000 * 2 for link/native ratio diff --git a/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol index 7011bb6016b..ba77686088e 100644 --- a/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol @@ -16,7 +16,8 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 ETH bytes32 private vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; uint32 private wrapperGasOverhead = 10_000; - uint32 private coordinatorGasOverhead = 20_000; + uint32 private coordinatorGasOverheadNative = 20_000; + uint32 private coordinatorGasOverheadLink = 40_000; uint256 private s_wrapperSubscriptionId; ExposedVRFCoordinatorV2_5 private s_testCoordinator; @@ -101,7 +102,8 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { function setConfigWrapper() internal { s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead - coordinatorGasOverhead, // coordinator gas overhead + coordinatorGasOverheadNative, // coordinator gas overhead native + coordinatorGasOverheadLink, // coordinator gas overhead link 0, // coordinator gas overhead per word 0, // native premium percentage, 0, // link premium percentage @@ -118,7 +120,8 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { , , uint32 _wrapperGasOverhead, - uint32 _coordinatorGasOverhead, + uint32 _coordinatorGasOverheadNative, + uint32 _coordinatorGasOverheadLink, uint16 _coordinatorGasOverheadPerWord, uint8 _coordinatorNativePremiumPercentage, uint8 _coordinatorLinkPremiumPercentage, @@ -126,7 +129,8 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { uint8 _maxNumWords ) = s_wrapper.getConfig(); assertEq(_wrapperGasOverhead, wrapperGasOverhead); - assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); + assertEq(_coordinatorGasOverheadNative, coordinatorGasOverheadNative); + assertEq(_coordinatorGasOverheadLink, coordinatorGasOverheadLink); assertEq(0, _coordinatorGasOverheadPerWord); assertEq(0, _coordinatorNativePremiumPercentage); assertEq(0, _coordinatorLinkPremiumPercentage); @@ -229,7 +233,7 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { assertEq(requestId, 1); (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); - uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead) * 2; + uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverheadLink) * 2; uint256 wrapperCostEstimate = s_wrapper.estimateRequestPrice(callbackGasLimit, 0, tx.gasprice); uint256 wrapperCostCalculation = s_wrapper.calculateRequestPrice(callbackGasLimit, 0); assertEq(paid, expectedPaid); // 1_030_000 * 2 for link/native ratio @@ -344,7 +348,7 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { assertEq(requestId, 1); (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); - uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead; + uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverheadNative; uint256 wrapperNativeCostEstimate = s_wrapper.estimateRequestPriceNative(callbackGasLimit, 0, tx.gasprice); uint256 wrapperCostCalculation = s_wrapper.calculateRequestPriceNative(callbackGasLimit, 0); assertEq(paid, expectedPaid); diff --git a/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts index 47fc6f13e73..02191dab999 100644 --- a/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts @@ -232,6 +232,7 @@ describe('AutomationRegistrar2_3', () => { priceFeed: await registry.getLinkUSDFeedAddress(), fallbackPrice: 200, minSpend: minimumRegistrationAmount, + decimals: 18, }, ], ) diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts index 1036ab2ce88..e7480dd869a 100644 --- a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts @@ -667,6 +667,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: minUpkeepSpend, + decimals: 18, }, ], ) @@ -957,6 +958,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: minUpkeepSpend, + decimals: 18, }, ], ] @@ -976,6 +978,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: minUpkeepSpend, + decimals: 18, }, ], ] @@ -995,6 +998,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: minUpkeepSpend, + decimals: 18, }, ], ] @@ -4743,6 +4747,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: newMinUpkeepSpend, + decimals: 18, }, ], ) @@ -5258,6 +5263,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: newMinUpkeepSpend, + decimals: 18, }, ], ) @@ -5324,6 +5330,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: newMinUpkeepSpend, + decimals: 18, }, ], ) @@ -5385,6 +5392,7 @@ describe('AutomationRegistry2_3', () => { priceFeed: linkUSDFeed.address, fallbackPrice: fallbackLinkPrice, minSpend: newMinUpkeepSpend, + decimals: 18, }, ], ) diff --git a/core/bridges/mocks/orm.go b/core/bridges/mocks/orm.go index 836f667bbeb..30dfc3e33ea 100644 --- a/core/bridges/mocks/orm.go +++ b/core/bridges/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/bridges/orm_test.go b/core/bridges/orm_test.go index 204dc5fe115..85e8b9ecdef 100644 --- a/core/bridges/orm_test.go +++ b/core/bridges/orm_test.go @@ -17,7 +17,6 @@ import ( "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/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -144,8 +143,8 @@ func TestORM_TestCachedResponse(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := bridges.NewORM(db) - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(ctx, nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) _, err = orm.GetCachedResponse(ctx, "dot", specID, 1*time.Second) diff --git a/core/capabilities/registry_test.go b/core/capabilities/registry_test.go index 3f8ca397495..3bed31a957a 100644 --- a/core/capabilities/registry_test.go +++ b/core/capabilities/registry_test.go @@ -19,8 +19,8 @@ type mockCapability struct { capabilities.CapabilityInfo } -func (m *mockCapability) Execute(ctx context.Context, callback chan<- capabilities.CapabilityResponse, req capabilities.CapabilityRequest) error { - return nil +func (m *mockCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + return nil, nil } func (m *mockCapability) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { @@ -140,7 +140,7 @@ func TestRegistry_ChecksExecutionAPIByType(t *testing.T) { { name: "trigger", newCapability: func(ctx context.Context, reg *coreCapabilities.Registry) (string, error) { - odt := triggers.NewOnDemand() + odt := triggers.NewOnDemand(logger.TestLogger(t)) info, err := odt.Info(ctx) require.NoError(t, err) return info.ID, reg.Add(ctx, odt) diff --git a/core/capabilities/remote/dispatcher.go b/core/capabilities/remote/dispatcher.go index f25d8cb784a..44b00c035f1 100644 --- a/core/capabilities/remote/dispatcher.go +++ b/core/capabilities/remote/dispatcher.go @@ -9,7 +9,7 @@ import ( "google.golang.org/protobuf/proto" "github.com/smartcontractkit/chainlink-common/pkg/services" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" @@ -23,7 +23,7 @@ type dispatcher struct { peer p2ptypes.Peer peerID p2ptypes.PeerID signer p2ptypes.Signer - registry commontypes.CapabilitiesRegistry + registry core.CapabilitiesRegistry receivers map[key]remotetypes.Receiver mu sync.RWMutex stopCh services.StopChan @@ -40,7 +40,7 @@ var _ services.Service = &dispatcher{} const supportedVersion = 1 -func NewDispatcher(peerWrapper p2ptypes.PeerWrapper, signer p2ptypes.Signer, registry commontypes.CapabilitiesRegistry, lggr logger.Logger) *dispatcher { +func NewDispatcher(peerWrapper p2ptypes.PeerWrapper, signer p2ptypes.Signer, registry core.CapabilitiesRegistry, lggr logger.Logger) *dispatcher { return &dispatcher{ peerWrapper: peerWrapper, signer: signer, diff --git a/core/capabilities/remote/target.go b/core/capabilities/remote/target.go index bacc06c0310..92b0724512a 100644 --- a/core/capabilities/remote/target.go +++ b/core/capabilities/remote/target.go @@ -50,7 +50,7 @@ func (c *remoteTargetCaller) UnregisterFromWorkflow(ctx context.Context, request return errors.New("not implemented") } -func (c *remoteTargetCaller) Execute(ctx context.Context, callback chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { +func (c *remoteTargetCaller) Execute(ctx context.Context, request commoncap.CapabilityRequest) (<-chan commoncap.CapabilityResponse, error) { c.lggr.Debugw("not implemented - executing fake remote target capability", "capabilityId", c.capInfo.ID, "nMembers", len(c.donInfo.Members)) for _, peerID := range c.donInfo.Members { m := &types.MessageBody{ @@ -60,10 +60,12 @@ func (c *remoteTargetCaller) Execute(ctx context.Context, callback chan<- common } err := c.dispatcher.Send(peerID, m) if err != nil { - return err + return nil, err } } - return nil + + // TODO: return a channel that will be closed when all responses are received + return nil, nil } func (c *remoteTargetCaller) Receive(msg *types.MessageBody) { diff --git a/core/capabilities/remote/target_test.go b/core/capabilities/remote/target_test.go index 904cd5b9c71..a9e72d778df 100644 --- a/core/capabilities/remote/target_test.go +++ b/core/capabilities/remote/target_test.go @@ -3,8 +3,8 @@ package remote_test import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" @@ -24,5 +24,7 @@ func TestTarget_Placeholder(t *testing.T) { dispatcher := remoteMocks.NewDispatcher(t) dispatcher.On("Send", mock.Anything, mock.Anything).Return(nil) target := remote.NewRemoteTargetCaller(commoncap.CapabilityInfo{}, donInfo, dispatcher, lggr) - require.NoError(t, target.Execute(ctx, nil, commoncap.CapabilityRequest{})) + + _, err := target.Execute(ctx, commoncap.CapabilityRequest{}) + assert.NoError(t, err) } diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go index 94ca58e6156..d06254657c7 100644 --- a/core/capabilities/remote/trigger_publisher.go +++ b/core/capabilities/remote/trigger_publisher.go @@ -5,6 +5,7 @@ import ( sync "sync" "time" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -40,7 +41,7 @@ type registrationKey struct { } type pubRegState struct { - callback chan<- commoncap.CapabilityResponse + callback <-chan commoncap.CapabilityResponse request commoncap.CapabilityRequest } @@ -87,17 +88,21 @@ func (p *triggerPublisher) Receive(msg *types.MessageBody) { key := registrationKey{msg.CallerDonId, req.Metadata.WorkflowID} nowMs := time.Now().UnixMilli() p.mu.Lock() + defer p.mu.Unlock() p.messageCache.Insert(key, sender, nowMs, msg.Payload) + _, exists := p.registrations[key] + if exists { + p.lggr.Debugw("trigger registration already exists", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID) + return + } // NOTE: require 2F+1 by default, introduce different strategies later (KS-76) minRequired := uint32(2*callerDon.F + 1) ready, payloads := p.messageCache.Ready(key, minRequired, nowMs-int64(p.config.RegistrationExpiryMs), false) - p.mu.Unlock() if !ready { p.lggr.Debugw("not ready to aggregate yet", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "minRequired", minRequired) return } - agg := NewDefaultModeAggregator(uint32(callerDon.F + 1)) - aggregated, err := agg.Aggregate("", payloads) + aggregated, err := AggregateModeRaw(payloads, uint32(callerDon.F+1)) if err != nil { p.lggr.Errorw("failed to aggregate trigger registrations", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err) return @@ -107,10 +112,8 @@ func (p *triggerPublisher) Receive(msg *types.MessageBody) { p.lggr.Errorw("failed to unmarshal request", "capabilityId", p.capInfo.ID, "err", err) return } - p.mu.Lock() - callbackCh := make(chan commoncap.CapabilityResponse) ctx, cancel := p.stopCh.NewCtx() - err = p.underlying.RegisterTrigger(ctx, callbackCh, unmarshaled) + callbackCh, err := p.underlying.RegisterTrigger(ctx, unmarshaled) cancel() if err == nil { p.registrations[key] = &pubRegState{ @@ -123,7 +126,6 @@ func (p *triggerPublisher) Receive(msg *types.MessageBody) { } else { p.lggr.Errorw("failed to register trigger", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err) } - p.mu.Unlock() } else { p.lggr.Errorw("received trigger request with unknown method", "method", msg.Method, "sender", sender) } @@ -150,7 +152,6 @@ func (p *triggerPublisher) registrationCleanupLoop() { cancel() p.lggr.Infow("unregistered trigger", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonId, "workflowId", key.workflowId, "err", err) // after calling UnregisterTrigger, the underlying trigger will not send any more events to the channel - close(req.callback) delete(p.registrations, key) p.messageCache.Delete(key) } @@ -160,7 +161,7 @@ func (p *triggerPublisher) registrationCleanupLoop() { } } -func (p *triggerPublisher) triggerEventLoop(callbackCh chan commoncap.CapabilityResponse, key registrationKey) { +func (p *triggerPublisher) triggerEventLoop(callbackCh <-chan commoncap.CapabilityResponse, key registrationKey) { defer p.wg.Done() for { select { @@ -171,7 +172,13 @@ func (p *triggerPublisher) triggerEventLoop(callbackCh chan commoncap.Capability p.lggr.Infow("triggerEventLoop channel closed", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId) return } - p.lggr.Debugw("received trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId) + triggerEvent := capabilities.TriggerEvent{} + err := response.Value.UnwrapTo(&triggerEvent) + if err != nil { + p.lggr.Errorw("can't unwrap trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId, "err", err) + break + } + p.lggr.Debugw("received trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId, "triggerEventID", triggerEvent.ID) marshaled, err := pb.MarshalCapabilityResponse(response) if err != nil { p.lggr.Debugw("can't marshal trigger event", "err", err) @@ -186,7 +193,8 @@ func (p *triggerPublisher) triggerEventLoop(callbackCh chan commoncap.Capability Metadata: &types.MessageBody_TriggerEventMetadata{ TriggerEventMetadata: &types.TriggerEventMetadata{ // NOTE: optionally introduce batching across workflows as an optimization - WorkflowIds: []string{key.workflowId}, + WorkflowIds: []string{key.workflowId}, + TriggerEventId: triggerEvent.ID, }, }, } diff --git a/core/capabilities/remote/trigger_publisher_test.go b/core/capabilities/remote/trigger_publisher_test.go index 2a31646de5b..dd107e12e61 100644 --- a/core/capabilities/remote/trigger_publisher_test.go +++ b/core/capabilities/remote/trigger_publisher_test.go @@ -87,9 +87,9 @@ func (t *testTrigger) Info(_ context.Context) (commoncap.CapabilityInfo, error) return t.info, nil } -func (t *testTrigger) RegisterTrigger(_ context.Context, _ chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { +func (t *testTrigger) RegisterTrigger(_ context.Context, request commoncap.CapabilityRequest) (<-chan commoncap.CapabilityResponse, error) { t.registrationsCh <- request - return nil + return nil, nil } func (t *testTrigger) UnregisterTrigger(_ context.Context, request commoncap.CapabilityRequest) error { diff --git a/core/capabilities/remote/trigger_subscriber.go b/core/capabilities/remote/trigger_subscriber.go index 2c893d2b86e..a7cb58c008b 100644 --- a/core/capabilities/remote/trigger_subscriber.go +++ b/core/capabilities/remote/trigger_subscriber.go @@ -51,7 +51,11 @@ var _ commoncap.TriggerCapability = &triggerSubscriber{} var _ types.Receiver = &triggerSubscriber{} var _ services.Service = &triggerSubscriber{} -func NewTriggerSubscriber(config types.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo types.DON, localDonInfo types.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { +// TODO makes this configurable with a default +const defaultSendChannelBufferSize = 1000 + +func NewTriggerSubscriber(config types.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo types.DON, localDonInfo types.DON, + dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { if aggregator == nil { lggr.Warnw("no aggregator provided, using default MODE aggregator", "capabilityId", capInfo.ID) aggregator = NewDefaultModeAggregator(uint32(capDonInfo.F + 1)) @@ -88,21 +92,25 @@ func (s *triggerSubscriber) Info(ctx context.Context) (commoncap.CapabilityInfo, return s.capInfo, nil } -func (s *triggerSubscriber) RegisterTrigger(ctx context.Context, callback chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { +func (s *triggerSubscriber) RegisterTrigger(ctx context.Context, request commoncap.CapabilityRequest) (<-chan commoncap.CapabilityResponse, error) { rawRequest, err := pb.MarshalCapabilityRequest(request) if err != nil { - return err + return nil, err } if request.Metadata.WorkflowID == "" { - return errors.New("empty workflowID") + return nil, errors.New("empty workflowID") } s.mu.Lock() defer s.mu.Unlock() + + callback := make(chan commoncap.CapabilityResponse, defaultSendChannelBufferSize) s.registeredWorkflows[request.Metadata.WorkflowID] = &subRegState{ callback: callback, rawRequest: rawRequest, } - return nil + + s.lggr.Infow("RegisterTrigger called", "capabilityId", s.capInfo.ID, "donId", s.capDonInfo.ID, "workflowID", request.Metadata.WorkflowID) + return callback, nil } func (s *triggerSubscriber) registrationLoop() { @@ -114,8 +122,8 @@ func (s *triggerSubscriber) registrationLoop() { case <-s.stopCh: return case <-ticker.C: - s.lggr.Infow("register trigger for remote capability", "capabilityId", s.capInfo.ID, "donId", s.capDonInfo.ID, "nMembers", len(s.capDonInfo.Members)) s.mu.RLock() + s.lggr.Infow("register trigger for remote capability", "capabilityId", s.capInfo.ID, "donId", s.capDonInfo.ID, "nMembers", len(s.capDonInfo.Members), "nWorkflows", len(s.registeredWorkflows)) for _, registration := range s.registeredWorkflows { // NOTE: send to all by default, introduce different strategies later (KS-76) for _, peerID := range s.capDonInfo.Members { @@ -140,6 +148,8 @@ func (s *triggerSubscriber) registrationLoop() { func (s *triggerSubscriber) UnregisterTrigger(ctx context.Context, request commoncap.CapabilityRequest) error { s.mu.Lock() defer s.mu.Unlock() + + close(s.registeredWorkflows[request.Metadata.WorkflowID].callback) delete(s.registeredWorkflows, request.Metadata.WorkflowID) // Registrations will quickly expire on all remote nodes. // Alternatively, we could send UnregisterTrigger messages right away. @@ -180,18 +190,14 @@ func (s *triggerSubscriber) Receive(msg *types.MessageBody) { continue } if ready { + s.lggr.Debugw("trigger event ready to aggregate", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) aggregatedResponse, err := s.aggregator.Aggregate(meta.TriggerEventId, payloads) if err != nil { - s.lggr.Errorw("failed to aggregate responses", "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) - continue - } - unmarshaled, err := pb.UnmarshalCapabilityResponse(aggregatedResponse) - if err != nil { - s.lggr.Errorw("failed to unmarshal responses", "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) + s.lggr.Errorw("failed to aggregate responses", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) continue } - s.lggr.Info("remote trigger event aggregated", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) - registration.callback <- unmarshaled + s.lggr.Infow("remote trigger event aggregated", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) + registration.callback <- aggregatedResponse } } } else { diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go index ce901169f10..df04306e2b0 100644 --- a/core/capabilities/remote/trigger_subscriber_test.go +++ b/core/capabilities/remote/trigger_subscriber_test.go @@ -67,12 +67,13 @@ func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { } subscriber := remote.NewTriggerSubscriber(config, capInfo, capDonInfo, workflowDonInfo, dispatcher, nil, lggr) require.NoError(t, subscriber.Start(ctx)) - triggerEventCallbackCh := make(chan commoncap.CapabilityResponse, 2) - require.NoError(t, subscriber.RegisterTrigger(ctx, triggerEventCallbackCh, commoncap.CapabilityRequest{ + + triggerEventCallbackCh, err := subscriber.RegisterTrigger(ctx, commoncap.CapabilityRequest{ Metadata: commoncap.RequestMetadata{ WorkflowID: workflowID1, }, - })) + }) + require.NoError(t, err) <-awaitRegistrationMessageCh // receive trigger event diff --git a/core/capabilities/remote/types/mocks/dispatcher.go b/core/capabilities/remote/types/mocks/dispatcher.go index 8675e6153ac..9ef7cee78d1 100644 --- a/core/capabilities/remote/types/mocks/dispatcher.go +++ b/core/capabilities/remote/types/mocks/dispatcher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/remote/types/mocks/receiver.go b/core/capabilities/remote/types/mocks/receiver.go index a15c464450e..bc41baa5496 100644 --- a/core/capabilities/remote/types/mocks/receiver.go +++ b/core/capabilities/remote/types/mocks/receiver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/remote/types/types.go b/core/capabilities/remote/types/types.go index 327c2b8d4c5..d8307d09f80 100644 --- a/core/capabilities/remote/types/types.go +++ b/core/capabilities/remote/types/types.go @@ -1,6 +1,7 @@ package types import ( + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) @@ -23,7 +24,7 @@ type Receiver interface { } type Aggregator interface { - Aggregate(eventID string, responses [][]byte) ([]byte, error) + Aggregate(eventID string, responses [][]byte) (commoncap.CapabilityResponse, error) } // NOTE: this type will become part of the Registry (KS-108) diff --git a/core/capabilities/remote/utils.go b/core/capabilities/remote/utils.go index 92c5e5447a5..dba24b843cc 100644 --- a/core/capabilities/remote/utils.go +++ b/core/capabilities/remote/utils.go @@ -10,6 +10,8 @@ import ( "google.golang.org/protobuf/proto" + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) @@ -60,16 +62,29 @@ func NewDefaultModeAggregator(minIdenticalResponses uint32) *defaultModeAggregat } } -func (a *defaultModeAggregator) Aggregate(_ string, responses [][]byte) ([]byte, error) { +func (a *defaultModeAggregator) Aggregate(_ string, responses [][]byte) (commoncap.CapabilityResponse, error) { + found, err := AggregateModeRaw(responses, a.minIdenticalResponses) + if err != nil { + return commoncap.CapabilityResponse{}, fmt.Errorf("failed to aggregate responses, err: %w", err) + } + + unmarshaled, err := pb.UnmarshalCapabilityResponse(found) + if err != nil { + return commoncap.CapabilityResponse{}, fmt.Errorf("failed to unmarshal aggregated responses, err: %w", err) + } + return unmarshaled, nil +} + +func AggregateModeRaw(elemList [][]byte, minIdenticalResponses uint32) ([]byte, error) { hashToCount := make(map[string]uint32) var found []byte - for _, resp := range responses { + for _, elem := range elemList { hasher := sha256.New() - hasher.Write(resp) + hasher.Write(elem) sha := hex.EncodeToString(hasher.Sum(nil)) hashToCount[sha]++ - if hashToCount[sha] >= a.minIdenticalResponses { - found = resp + if hashToCount[sha] >= minIdenticalResponses { + found = elem break } } diff --git a/core/capabilities/remote/utils_test.go b/core/capabilities/remote/utils_test.go index 120cf5604ca..b5f97af99ed 100644 --- a/core/capabilities/remote/utils_test.go +++ b/core/capabilities/remote/utils_test.go @@ -1,7 +1,6 @@ package remote_test import ( - "bytes" "crypto/ed25519" "crypto/rand" "testing" @@ -90,29 +89,32 @@ func TestToPeerID(t *testing.T) { } func TestDefaultModeAggregator_Aggregate(t *testing.T) { - capResponse1 := marshalCapabilityResponse(t, triggerEvent1, nil) - capResponse2 := marshalCapabilityResponse(t, triggerEvent2, nil) + val, err := values.Wrap(triggerEvent1) + require.NoError(t, err) + capResponse1 := commoncap.CapabilityResponse{ + Value: val, + Err: nil, + } + marshaled1, err := pb.MarshalCapabilityResponse(capResponse1) + require.NoError(t, err) + + val2, err := values.Wrap(triggerEvent2) + require.NoError(t, err) + capResponse2 := commoncap.CapabilityResponse{ + Value: val2, + Err: nil, + } + marshaled2, err := pb.MarshalCapabilityResponse(capResponse2) + require.NoError(t, err) agg := remote.NewDefaultModeAggregator(2) - _, err := agg.Aggregate("", [][]byte{capResponse1}) + _, err = agg.Aggregate("", [][]byte{marshaled1}) require.Error(t, err) - _, err = agg.Aggregate("", [][]byte{capResponse1, capResponse2}) + _, err = agg.Aggregate("", [][]byte{marshaled1, marshaled2}) require.Error(t, err) - res, err := agg.Aggregate("", [][]byte{capResponse1, capResponse2, capResponse1}) - require.NoError(t, err) - require.True(t, bytes.Equal(res, capResponse1)) -} - -func marshalCapabilityResponse(t *testing.T, capValue any, capError error) []byte { - val, err := values.Wrap(capValue) - require.NoError(t, err) - capResponse := commoncap.CapabilityResponse{ - Value: val, - Err: capError, - } - marshaled, err := pb.MarshalCapabilityResponse(capResponse) + res, err := agg.Aggregate("", [][]byte{marshaled1, marshaled2, marshaled1}) require.NoError(t, err) - return marshaled + require.Equal(t, res, capResponse1) } diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index 748910c462b..dc9126dba36 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -3,10 +3,14 @@ package capabilities import ( "context" "slices" + "sync" + "time" 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" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/libocr/ragep2p" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" @@ -19,7 +23,7 @@ import ( type registrySyncer struct { peerWrapper p2ptypes.PeerWrapper - registry types.CapabilitiesRegistry + registry core.CapabilitiesRegistry dispatcher remotetypes.Dispatcher subServices []services.Service lggr logger.Logger @@ -32,17 +36,17 @@ var defaultStreamConfig = p2ptypes.StreamConfig{ OutgoingMessageBufferSize: 1000000, MaxMessageLenBytes: 100000, MessageRateLimiter: ragep2p.TokenBucketParams{ - Rate: 10.0, + Rate: 100.0, Capacity: 1000, }, BytesRateLimiter: ragep2p.TokenBucketParams{ - Rate: 10.0, - Capacity: 1000, + Rate: 100000.0, + Capacity: 1000000, }, } // RegistrySyncer updates local Registry to match its onchain counterpart -func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry types.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger) *registrySyncer { +func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry core.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger) *registrySyncer { return ®istrySyncer{ peerWrapper: peerWrapper, registry: registry, @@ -54,14 +58,16 @@ func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry types.Capabili func (s *registrySyncer) Start(ctx context.Context) error { // NOTE: temporary hard-coded DONs workflowDONPeers := []string{ - "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC", - "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8", - "12D3KooWJbZLiMuGeKw78s3LM5TNgBTJHcF39DraxLu14bucG9RN", - "12D3KooWGqfSPhHKmQycfhRjgUDE2vg9YWZN27Eue8idb2ZUk6EH", + "12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N", + "12D3KooWG1AyvwmCpZ93J8pBQUE1SuzrjDXnT4BeouncHR3jWLCG", + "12D3KooWGeUKZBRMbx27FUTgBwZa9Ap9Ym92mywwpuqkEtz8XWyv", + "12D3KooW9zYWQv3STmDeNDidyzxsJSTxoCTLicafgfeEz9nhwhC4", } - capabilityDONPeers := []string{ - "12D3KooWHCcyTPmYFB1ydNvNcXw5WyAomRzGSFu1B7hpB4yi8Smf", - "12D3KooWPv6eqJvYz7TcQWk4Y4XjZ1uQ7mUKahdDXj65ht95zH6a", + triggerDONPeers := []string{ + "12D3KooWJrthXtnPHw7xyHFAxo6NxifYTvc8igKYaA6wRRRqtsMb", + "12D3KooWFQekP9sGex4XhqEJav5EScjTpDVtDqJFg1JvrePBCEGJ", + "12D3KooWFLEq4hYtdyKWwe47dXGEbSiHMZhmr5xLSJNhpfiEz8NF", + "12D3KooWN2hztiXNNS1jMQTTvvPRYcarK1C7T3Mdqk4x4gwyo5WS", } allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) addPeersToDONInfo := func(peers []string, donInfo *remotetypes.DON) error { @@ -76,12 +82,12 @@ func (s *registrySyncer) Start(ctx context.Context) error { } return nil } - workflowDonInfo := remotetypes.DON{ID: "workflowDon1"} + workflowDonInfo := remotetypes.DON{ID: "workflowDon1", F: 1} if err := addPeersToDONInfo(workflowDONPeers, &workflowDonInfo); err != nil { return err } - capabilityDonInfo := remotetypes.DON{ID: "capabilityDon1"} - if err := addPeersToDONInfo(capabilityDONPeers, &capabilityDonInfo); err != nil { + triggerCapabilityDonInfo := remotetypes.DON{ID: "capabilityDon1", F: 1} + if err := addPeersToDONInfo(triggerDONPeers, &triggerCapabilityDonInfo); err != nil { return err } err := s.peerWrapper.GetPeer().UpdateConnections(allPeers) @@ -89,7 +95,7 @@ func (s *registrySyncer) Start(ctx context.Context) error { return err } // NOTE: temporary hard-coded capabilities - capId := "sample_remote_trigger" + capId := "mercury-trigger" triggerInfo := commoncap.CapabilityInfo{ ID: capId, CapabilityType: commoncap.CapabilityTypeTrigger, @@ -98,36 +104,42 @@ func (s *registrySyncer) Start(ctx context.Context) error { } myId := s.peerWrapper.GetPeer().ID().String() config := remotetypes.RemoteTriggerConfig{ - RegistrationRefreshMs: 20000, + RegistrationRefreshMs: 20000, + MinResponsesToAggregate: uint32(triggerCapabilityDonInfo.F) + 1, } if slices.Contains(workflowDONPeers, myId) { s.lggr.Info("member of a workflow DON - starting remote subscribers") - triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, capabilityDonInfo, workflowDonInfo, s.dispatcher, nil, s.lggr) + aggregator := triggers.NewMercuryRemoteAggregator(s.lggr) + triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, triggerCapabilityDonInfo, workflowDonInfo, s.dispatcher, aggregator, s.lggr) err = s.registry.Add(ctx, triggerCap) if err != nil { s.lggr.Errorw("failed to add remote target capability to registry", "error", err) return err } - err = s.dispatcher.SetReceiver(capId, capabilityDonInfo.ID, triggerCap) + err = s.dispatcher.SetReceiver(capId, triggerCapabilityDonInfo.ID, triggerCap) if err != nil { - s.lggr.Errorw("failed to set receiver", "capabilityId", capId, "donId", capabilityDonInfo.ID, "error", err) + s.lggr.Errorw("workflow DON failed to set receiver", "capabilityId", capId, "donId", triggerCapabilityDonInfo.ID, "error", err) return err } s.subServices = append(s.subServices, triggerCap) } - if slices.Contains(capabilityDONPeers, myId) { + if slices.Contains(triggerDONPeers, myId) { s.lggr.Info("member of a capability DON - starting remote publishers") workflowDONs := map[string]remotetypes.DON{ workflowDonInfo.ID: workflowDonInfo, } - underlying := &noOpTrigger{info: triggerInfo, lggr: s.lggr} - triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, capabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) - err = s.dispatcher.SetReceiver(capId, capabilityDonInfo.ID, triggerCap) + underlying := triggers.NewMercuryTriggerService(1000, s.lggr) + triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, triggerCapabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) + err = s.dispatcher.SetReceiver(capId, triggerCapabilityDonInfo.ID, triggerCap) if err != nil { - s.lggr.Errorw("failed to set receiver", "capabilityId", capId, "donId", capabilityDonInfo.ID, "error", err) + s.lggr.Errorw("capability DON failed to set receiver", "capabilityId", capId, "donId", triggerCapabilityDonInfo.ID, "error", err) return err } + s.subServices = append(s.subServices, underlying) s.subServices = append(s.subServices, triggerCap) + // NOTE: temporary mock Mercury data producer + mockMercuryDataProducer := NewMockMercuryDataProducer(underlying, s.lggr) + s.subServices = append(s.subServices, mockMercuryDataProducer) } // NOTE: temporary service start - should be managed by capability creation for _, srv := range s.subServices { @@ -163,21 +175,86 @@ func (s *registrySyncer) Name() string { return "RegistrySyncer" } -type noOpTrigger struct { - info commoncap.CapabilityInfo - lggr logger.Logger +type mockMercuryDataProducer struct { + trigger *triggers.MercuryTriggerService + wg sync.WaitGroup + closeCh chan struct{} + lggr logger.Logger } -func (t *noOpTrigger) Info(_ context.Context) (commoncap.CapabilityInfo, error) { - return t.info, nil +var _ services.Service = &mockMercuryDataProducer{} + +func NewMockMercuryDataProducer(trigger *triggers.MercuryTriggerService, lggr logger.Logger) *mockMercuryDataProducer { + return &mockMercuryDataProducer{ + trigger: trigger, + closeCh: make(chan struct{}), + lggr: lggr, + } } -func (t *noOpTrigger) RegisterTrigger(_ context.Context, _ chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { - t.lggr.Infow("no-op trigger RegisterTrigger", "workflowID", request.Metadata.WorkflowID) +func (m *mockMercuryDataProducer) Start(ctx context.Context) error { + m.wg.Add(1) + go m.loop() return nil } -func (t *noOpTrigger) UnregisterTrigger(_ context.Context, request commoncap.CapabilityRequest) error { - t.lggr.Infow("no-op trigger RegisterTrigger", "workflowID", request.Metadata.WorkflowID) +func (m *mockMercuryDataProducer) loop() { + defer m.wg.Done() + + sleepSec := 60 + ticker := time.NewTicker(time.Duration(sleepSec) * time.Second) + defer ticker.Stop() + + prices := []int64{300000, 40000, 5000000} + + for range ticker.C { + for i := range prices { + prices[i] = prices[i] + 1 + } + + reports := []mercury.FeedReport{ + { + FeedID: "0x1111111111111111111100000000000000000000000000000000000000000000", + FullReport: []byte{0x11, 0xaa, 0xbb, 0xcc}, + BenchmarkPrice: prices[0], + ObservationTimestamp: time.Now().Unix(), + }, + { + FeedID: "0x2222222222222222222200000000000000000000000000000000000000000000", + FullReport: []byte{0x22, 0xaa, 0xbb, 0xcc}, + BenchmarkPrice: prices[1], + ObservationTimestamp: time.Now().Unix(), + }, + { + FeedID: "0x3333333333333333333300000000000000000000000000000000000000000000", + FullReport: []byte{0x33, 0xaa, 0xbb, 0xcc}, + BenchmarkPrice: prices[2], + ObservationTimestamp: time.Now().Unix(), + }, + } + + m.lggr.Infow("New set of Mercury reports", "timestamp", time.Now().Unix(), "payload", reports) + err := m.trigger.ProcessReport(reports) + if err != nil { + m.lggr.Errorw("failed to process Mercury reports", "err", err, "timestamp", time.Now().Unix(), "payload", reports) + } + } +} + +func (m *mockMercuryDataProducer) Close() error { + close(m.closeCh) + m.wg.Wait() + return nil +} + +func (m *mockMercuryDataProducer) HealthReport() map[string]error { return nil } + +func (m *mockMercuryDataProducer) Ready() error { + return nil +} + +func (m *mockMercuryDataProducer) Name() string { + return "mockMercuryDataProducer" +} diff --git a/core/capabilities/syncer_test.go b/core/capabilities/syncer_test.go index 335b9774689..757135635d8 100644 --- a/core/capabilities/syncer_test.go +++ b/core/capabilities/syncer_test.go @@ -20,7 +20,7 @@ func TestSyncer_CleanStartClose(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) var pid ragetypes.PeerID - err := pid.UnmarshalText([]byte("12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC")) + err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) require.NoError(t, err) peer := mocks.NewPeer(t) peer.On("UpdateConnections", mock.Anything).Return(nil) diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go index 677b1148ebb..47f1048211e 100644 --- a/core/capabilities/targets/write_target.go +++ b/core/capabilities/targets/write_target.go @@ -14,7 +14,7 @@ import ( chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-common/pkg/values" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" abiutil "github.com/smartcontractkit/chainlink/v2/core/chains/evm/abi" @@ -28,7 +28,7 @@ import ( var forwardABI = evmtypes.MustGetABI(forwarder.KeystoneForwarderMetaData.ABI) -func InitializeWrite(registry commontypes.CapabilitiesRegistry, legacyEVMChains legacyevm.LegacyChainContainer, lggr logger.Logger) error { +func InitializeWrite(registry core.CapabilitiesRegistry, legacyEVMChains legacyevm.LegacyChainContainer, lggr logger.Logger) error { for _, chain := range legacyEVMChains.Slice() { capability := NewEvmWrite(chain, lggr) if err := registry.Add(context.TODO(), capability); err != nil { @@ -157,7 +157,7 @@ func encodePayload(args []any, rawSelector string) ([]byte, error) { // return append(method.ID, arguments...), nil } -func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.CapabilityResponse, request capabilities.CapabilityRequest) error { +func (cap *EvmWrite) Execute(ctx context.Context, request capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { cap.lggr.Debugw("Execute", "request", request) // TODO: idempotency @@ -168,22 +168,23 @@ func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.C reqConfig, err := parseConfig(request.Config) if err != nil { - return err + return nil, err } inputsAny, err := request.Inputs.Unwrap() if err != nil { - return err + return nil, err } inputs := inputsAny.(map[string]any) rep, ok := inputs["report"] if !ok { - return errors.New("malformed data: inputs doesn't contain a report key") + return nil, errors.New("malformed data: inputs doesn't contain a report key") } if rep == nil { // We received any empty report -- this means we should skip transmission. cap.lggr.Debugw("Skipping empty report", "request", request) + callback := make(chan capabilities.CapabilityResponse) go func() { // TODO: cast tx.Error to Err (or Value to Value?) callback <- capabilities.CapabilityResponse{ @@ -192,18 +193,18 @@ func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.C } close(callback) }() - return nil + return callback, nil } // evaluate any variables in reqConfig.Params args, err := evaluateParams(reqConfig.Params, inputs) if err != nil { - return err + return nil, err } data, err := encodePayload(args, reqConfig.ABI) if err != nil { - return err + return nil, err } // TODO: validate encoded report is prefixed with workflowID and executionID that match the request meta @@ -214,7 +215,7 @@ func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.C // construct forwarding payload calldata, err := forwardABI.Pack("report", common.HexToAddress(reqConfig.Address), data, signatures) if err != nil { - return err + return nil, err } txMeta := &txmgr.TxMeta{ @@ -238,9 +239,11 @@ func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.C } tx, err := txm.CreateTransaction(ctx, req) if err != nil { - return err + return nil, err } cap.lggr.Debugw("Transaction submitted", "request", request, "transaction", tx) + + callback := make(chan capabilities.CapabilityResponse) go func() { // TODO: cast tx.Error to Err (or Value to Value?) callback <- capabilities.CapabilityResponse{ @@ -249,7 +252,7 @@ func (cap *EvmWrite) Execute(ctx context.Context, callback chan<- capabilities.C } close(callback) }() - return nil + return callback, nil } func (cap *EvmWrite) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index fd68234ca70..744fcd9d2e7 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -82,9 +82,7 @@ func TestEvmWrite(t *testing.T) { }) - ch := make(chan capabilities.CapabilityResponse) - - err = capability.Execute(ctx, ch, req) + ch, err := capability.Execute(ctx, req) require.NoError(t, err) response := <-ch @@ -134,9 +132,7 @@ func TestEvmWrite_EmptyReport(t *testing.T) { Inputs: inputs, } - ch := make(chan capabilities.CapabilityResponse) - - err = capability.Execute(ctx, ch, req) + ch, err := capability.Execute(ctx, req) require.NoError(t, err) response := <-ch diff --git a/core/chainlink.Dockerfile b/core/chainlink.Dockerfile index e82a4cd662c..4aa447b5ddd 100644 --- a/core/chainlink.Dockerfile +++ b/core/chainlink.Dockerfile @@ -45,7 +45,7 @@ RUN apt-get update && apt-get install -y ca-certificates gnupg lsb-release curl # Install Postgres for CLI tools, needed specifically for DB backups RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |tee /etc/apt/sources.list.d/pgdg.list \ - && apt-get update && apt-get install -y postgresql-client-15 \ + && apt-get update && apt-get install -y postgresql-client-16 \ && apt-get clean all \ && rm -rf /var/lib/apt/lists/* diff --git a/core/chainlink.goreleaser.Dockerfile b/core/chainlink.goreleaser.Dockerfile index 7dab088116e..5d172fd77e5 100644 --- a/core/chainlink.goreleaser.Dockerfile +++ b/core/chainlink.goreleaser.Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y ca-certificates gnupg lsb-release curl # Install Postgres for CLI tools, needed specifically for DB backups RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |tee /etc/apt/sources.list.d/pgdg.list \ - && apt-get update && apt-get install -y postgresql-client-15 \ + && apt-get update && apt-get install -y postgresql-client-16 \ && apt-get clean all \ && rm -rf /var/lib/apt/lists/* diff --git a/core/chains/evm/client/mocks/batch_sender.go b/core/chains/evm/client/mocks/batch_sender.go index 3d65749b5bc..f6a3601ceab 100644 --- a/core/chains/evm/client/mocks/batch_sender.go +++ b/core/chains/evm/client/mocks/batch_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index b3cdac3a6b6..58d51526626 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/client/mocks/rpc_client.go b/core/chains/evm/client/mocks/rpc_client.go index 9fd9d6a9e79..980a215ccfe 100644 --- a/core/chains/evm/client/mocks/rpc_client.go +++ b/core/chains/evm/client/mocks/rpc_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/client/mocks/tx_sender.go b/core/chains/evm/client/mocks/tx_sender.go index a769a786a18..6c44544508b 100644 --- a/core/chains/evm/client/mocks/tx_sender.go +++ b/core/chains/evm/client/mocks/tx_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index cdc14f6aed2..8f94fef09f4 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -4,29 +4,21 @@ import ( "math/big" "time" - "go.uber.org/multierr" - - ocr "github.com/smartcontractkit/libocr/offchainreporting" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/logger" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/config" ) -func NewTOMLChainScopedConfig(appCfg config.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { +func NewTOMLChainScopedConfig(tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { return &ChainScoped{ - AppConfig: appCfg, evmConfig: &EVMConfig{C: tomlConfig}, lggr: lggr} } // ChainScoped implements config.ChainScopedConfig with a gencfg.BasicConfig and EVMConfig. type ChainScoped struct { - config.AppConfig lggr logger.Logger evmConfig *EVMConfig @@ -44,24 +36,6 @@ func (c *ChainScoped) BlockEmissionIdleWarningThreshold() time.Duration { return c.EVM().NodeNoNewHeadsThreshold() } -func (c *ChainScoped) Validate() (err error) { - // Most per-chain validation is done on startup, but this combines globals as well. - lc := ocrtypes.LocalConfig{ - BlockchainTimeout: c.OCR().BlockchainTimeout(), - ContractConfigConfirmations: c.EVM().OCR().ContractConfirmations(), - ContractConfigTrackerPollInterval: c.OCR().ContractPollInterval(), - ContractConfigTrackerSubscribeInterval: c.OCR().ContractSubscribeInterval(), - ContractTransmitterTransmitTimeout: c.EVM().OCR().ContractTransmitterTransmitTimeout(), - DatabaseTimeout: c.EVM().OCR().DatabaseTimeout(), - DataSourceTimeout: c.OCR().ObservationTimeout(), - DataSourceGracePeriod: c.EVM().OCR().ObservationGracePeriod(), - } - if ocrerr := ocr.SanityCheckLocalConfig(lc); ocrerr != nil { - err = multierr.Append(err, ocrerr) - } - return -} - type EVMConfig struct { C *toml.EVMConfig } diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index bc538f1aa83..34de754de21 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -11,7 +11,6 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/config" ) type EVM interface { @@ -166,8 +165,5 @@ type NodePool interface { // //go:generate mockery --quiet --name ChainScopedConfig --output ./mocks/ --case=underscore type ChainScopedConfig interface { - config.AppConfig - Validate() error - EVM() EVM } diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index 29b6d6f3f3e..7f5f9666ae6 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -1,18 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" - mock "github.com/stretchr/testify/mock" - - time "time" - - uuid "github.com/google/uuid" - - zapcore "go.uber.org/zap/zapcore" ) // ChainScopedConfig is an autogenerated mock type for the ChainScopedConfig type @@ -20,124 +12,6 @@ type ChainScopedConfig struct { mock.Mock } -// AppID provides a mock function with given fields: -func (_m *ChainScopedConfig) AppID() uuid.UUID { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for AppID") - } - - var r0 uuid.UUID - if rf, ok := ret.Get(0).(func() uuid.UUID); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(uuid.UUID) - } - } - - return r0 -} - -// AuditLogger provides a mock function with given fields: -func (_m *ChainScopedConfig) AuditLogger() coreconfig.AuditLogger { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for AuditLogger") - } - - var r0 coreconfig.AuditLogger - if rf, ok := ret.Get(0).(func() coreconfig.AuditLogger); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.AuditLogger) - } - } - - return r0 -} - -// AutoPprof provides a mock function with given fields: -func (_m *ChainScopedConfig) AutoPprof() coreconfig.AutoPprof { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for AutoPprof") - } - - var r0 coreconfig.AutoPprof - if rf, ok := ret.Get(0).(func() coreconfig.AutoPprof); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.AutoPprof) - } - } - - return r0 -} - -// Capabilities provides a mock function with given fields: -func (_m *ChainScopedConfig) Capabilities() coreconfig.Capabilities { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Capabilities") - } - - var r0 coreconfig.Capabilities - if rf, ok := ret.Get(0).(func() coreconfig.Capabilities); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Capabilities) - } - } - - return r0 -} - -// CosmosEnabled provides a mock function with given fields: -func (_m *ChainScopedConfig) CosmosEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for CosmosEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Database provides a mock function with given fields: -func (_m *ChainScopedConfig) Database() coreconfig.Database { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Database") - } - - var r0 coreconfig.Database - if rf, ok := ret.Get(0).(func() coreconfig.Database); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Database) - } - } - - return r0 -} - // EVM provides a mock function with given fields: func (_m *ChainScopedConfig) EVM() config.EVM { ret := _m.Called() @@ -158,561 +32,6 @@ func (_m *ChainScopedConfig) EVM() config.EVM { return r0 } -// EVMEnabled provides a mock function with given fields: -func (_m *ChainScopedConfig) EVMEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for EVMEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// EVMRPCEnabled provides a mock function with given fields: -func (_m *ChainScopedConfig) EVMRPCEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for EVMRPCEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Feature provides a mock function with given fields: -func (_m *ChainScopedConfig) Feature() coreconfig.Feature { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Feature") - } - - var r0 coreconfig.Feature - if rf, ok := ret.Get(0).(func() coreconfig.Feature); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Feature) - } - } - - return r0 -} - -// FluxMonitor provides a mock function with given fields: -func (_m *ChainScopedConfig) FluxMonitor() coreconfig.FluxMonitor { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for FluxMonitor") - } - - var r0 coreconfig.FluxMonitor - if rf, ok := ret.Get(0).(func() coreconfig.FluxMonitor); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.FluxMonitor) - } - } - - return r0 -} - -// Insecure provides a mock function with given fields: -func (_m *ChainScopedConfig) Insecure() coreconfig.Insecure { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Insecure") - } - - var r0 coreconfig.Insecure - if rf, ok := ret.Get(0).(func() coreconfig.Insecure); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Insecure) - } - } - - return r0 -} - -// InsecureFastScrypt provides a mock function with given fields: -func (_m *ChainScopedConfig) InsecureFastScrypt() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for InsecureFastScrypt") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// JobPipeline provides a mock function with given fields: -func (_m *ChainScopedConfig) JobPipeline() coreconfig.JobPipeline { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for JobPipeline") - } - - var r0 coreconfig.JobPipeline - if rf, ok := ret.Get(0).(func() coreconfig.JobPipeline); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.JobPipeline) - } - } - - return r0 -} - -// Keeper provides a mock function with given fields: -func (_m *ChainScopedConfig) Keeper() coreconfig.Keeper { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Keeper") - } - - var r0 coreconfig.Keeper - if rf, ok := ret.Get(0).(func() coreconfig.Keeper); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Keeper) - } - } - - return r0 -} - -// Log provides a mock function with given fields: -func (_m *ChainScopedConfig) Log() coreconfig.Log { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Log") - } - - var r0 coreconfig.Log - if rf, ok := ret.Get(0).(func() coreconfig.Log); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Log) - } - } - - return r0 -} - -// LogConfiguration provides a mock function with given fields: log, warn -func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn, warn coreconfig.LogfFn) { - _m.Called(log, warn) -} - -// Mercury provides a mock function with given fields: -func (_m *ChainScopedConfig) Mercury() coreconfig.Mercury { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Mercury") - } - - var r0 coreconfig.Mercury - if rf, ok := ret.Get(0).(func() coreconfig.Mercury); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Mercury) - } - } - - return r0 -} - -// OCR provides a mock function with given fields: -func (_m *ChainScopedConfig) OCR() coreconfig.OCR { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for OCR") - } - - var r0 coreconfig.OCR - if rf, ok := ret.Get(0).(func() coreconfig.OCR); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.OCR) - } - } - - return r0 -} - -// OCR2 provides a mock function with given fields: -func (_m *ChainScopedConfig) OCR2() coreconfig.OCR2 { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for OCR2") - } - - var r0 coreconfig.OCR2 - if rf, ok := ret.Get(0).(func() coreconfig.OCR2); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.OCR2) - } - } - - return r0 -} - -// P2P provides a mock function with given fields: -func (_m *ChainScopedConfig) P2P() coreconfig.P2P { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for P2P") - } - - var r0 coreconfig.P2P - if rf, ok := ret.Get(0).(func() coreconfig.P2P); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.P2P) - } - } - - return r0 -} - -// Password provides a mock function with given fields: -func (_m *ChainScopedConfig) Password() coreconfig.Password { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Password") - } - - var r0 coreconfig.Password - if rf, ok := ret.Get(0).(func() coreconfig.Password); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Password) - } - } - - return r0 -} - -// Prometheus provides a mock function with given fields: -func (_m *ChainScopedConfig) Prometheus() coreconfig.Prometheus { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Prometheus") - } - - var r0 coreconfig.Prometheus - if rf, ok := ret.Get(0).(func() coreconfig.Prometheus); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Prometheus) - } - } - - return r0 -} - -// Pyroscope provides a mock function with given fields: -func (_m *ChainScopedConfig) Pyroscope() coreconfig.Pyroscope { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Pyroscope") - } - - var r0 coreconfig.Pyroscope - if rf, ok := ret.Get(0).(func() coreconfig.Pyroscope); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Pyroscope) - } - } - - return r0 -} - -// RootDir provides a mock function with given fields: -func (_m *ChainScopedConfig) RootDir() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for RootDir") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Sentry provides a mock function with given fields: -func (_m *ChainScopedConfig) Sentry() coreconfig.Sentry { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Sentry") - } - - var r0 coreconfig.Sentry - if rf, ok := ret.Get(0).(func() coreconfig.Sentry); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Sentry) - } - } - - return r0 -} - -// SetLogLevel provides a mock function with given fields: lvl -func (_m *ChainScopedConfig) SetLogLevel(lvl zapcore.Level) error { - ret := _m.Called(lvl) - - if len(ret) == 0 { - panic("no return value specified for SetLogLevel") - } - - var r0 error - if rf, ok := ret.Get(0).(func(zapcore.Level) error); ok { - r0 = rf(lvl) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SetLogSQL provides a mock function with given fields: logSQL -func (_m *ChainScopedConfig) SetLogSQL(logSQL bool) { - _m.Called(logSQL) -} - -// SetPasswords provides a mock function with given fields: keystore, vrf -func (_m *ChainScopedConfig) SetPasswords(keystore *string, vrf *string) { - _m.Called(keystore, vrf) -} - -// ShutdownGracePeriod provides a mock function with given fields: -func (_m *ChainScopedConfig) ShutdownGracePeriod() time.Duration { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ShutdownGracePeriod") - } - - var r0 time.Duration - if rf, ok := ret.Get(0).(func() time.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Duration) - } - - return r0 -} - -// SolanaEnabled provides a mock function with given fields: -func (_m *ChainScopedConfig) SolanaEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for SolanaEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// StarkNetEnabled provides a mock function with given fields: -func (_m *ChainScopedConfig) StarkNetEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for StarkNetEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// TelemetryIngress provides a mock function with given fields: -func (_m *ChainScopedConfig) TelemetryIngress() coreconfig.TelemetryIngress { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for TelemetryIngress") - } - - var r0 coreconfig.TelemetryIngress - if rf, ok := ret.Get(0).(func() coreconfig.TelemetryIngress); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.TelemetryIngress) - } - } - - return r0 -} - -// Threshold provides a mock function with given fields: -func (_m *ChainScopedConfig) Threshold() coreconfig.Threshold { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Threshold") - } - - var r0 coreconfig.Threshold - if rf, ok := ret.Get(0).(func() coreconfig.Threshold); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Threshold) - } - } - - return r0 -} - -// Tracing provides a mock function with given fields: -func (_m *ChainScopedConfig) Tracing() coreconfig.Tracing { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Tracing") - } - - var r0 coreconfig.Tracing - if rf, ok := ret.Get(0).(func() coreconfig.Tracing); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Tracing) - } - } - - return r0 -} - -// Validate provides a mock function with given fields: -func (_m *ChainScopedConfig) Validate() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Validate") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ValidateDB provides a mock function with given fields: -func (_m *ChainScopedConfig) ValidateDB() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ValidateDB") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// WebServer provides a mock function with given fields: -func (_m *ChainScopedConfig) WebServer() coreconfig.WebServer { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for WebServer") - } - - var r0 coreconfig.WebServer - if rf, ok := ret.Get(0).(func() coreconfig.WebServer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.WebServer) - } - } - - return r0 -} - // NewChainScopedConfig creates a new instance of ChainScopedConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewChainScopedConfig(t interface { diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index b1eb2b49b5c..549f16fe558 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index f0786c091c4..7a7a274127f 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -54,13 +54,13 @@ type FwdMgr struct { wg sync.WaitGroup } -func NewFwdMgr(db sqlutil.DataSource, client evmclient.Client, logpoller evmlogpoller.LogPoller, l logger.Logger, cfg Config) *FwdMgr { +func NewFwdMgr(ds sqlutil.DataSource, client evmclient.Client, logpoller evmlogpoller.LogPoller, l logger.Logger, cfg Config) *FwdMgr { lggr := logger.Sugared(logger.Named(l, "EVMForwarderManager")) fwdMgr := FwdMgr{ logger: lggr, cfg: cfg, evmClient: client, - ORM: NewORM(db), + ORM: NewORM(ds), logpoller: logpoller, sendersCache: make(map[common.Address][]common.Address), } diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index 795c74e27e9..04e252fa7d4 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index cf498518d6d..8076cba4831 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -23,50 +23,50 @@ type ORM interface { FindForwardersInListByChain(ctx context.Context, evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) } -type DbORM struct { - db sqlutil.DataSource +type DSORM struct { + ds sqlutil.DataSource } -var _ ORM = &DbORM{} +var _ ORM = &DSORM{} -func NewORM(db sqlutil.DataSource) *DbORM { - return &DbORM{db: db} +func NewORM(ds sqlutil.DataSource) *DSORM { + return &DSORM{ds: ds} } -func (o *DbORM) Transaction(ctx context.Context, fn func(*DbORM) error) (err error) { - return sqlutil.Transact(ctx, o.new, o.db, nil, fn) +func (o *DSORM) Transact(ctx context.Context, fn func(*DSORM) error) (err error) { + return sqlutil.Transact(ctx, o.new, o.ds, nil, fn) } // new returns a NewORM like o, but backed by q. -func (o *DbORM) new(q sqlutil.DataSource) *DbORM { return NewORM(q) } +func (o *DSORM) new(q sqlutil.DataSource) *DSORM { return NewORM(q) } // CreateForwarder creates the Forwarder address associated with the current EVM chain id. -func (o *DbORM) CreateForwarder(ctx context.Context, addr common.Address, evmChainId big.Big) (fwd Forwarder, err error) { +func (o *DSORM) CreateForwarder(ctx context.Context, addr common.Address, evmChainId big.Big) (fwd Forwarder, err error) { sql := `INSERT INTO evm.forwarders (address, evm_chain_id, created_at, updated_at) VALUES ($1, $2, now(), now()) RETURNING *` - err = o.db.GetContext(ctx, &fwd, sql, addr, evmChainId) + err = o.ds.GetContext(ctx, &fwd, sql, addr, evmChainId) return fwd, err } // DeleteForwarder removes a forwarder address. // If cleanup is non-nil, it can be used to perform any chain- or contract-specific cleanup that need to happen atomically // on forwarder deletion. If cleanup returns an error, forwarder deletion will be aborted. -func (o *DbORM) DeleteForwarder(ctx context.Context, id int64, cleanup func(tx sqlutil.DataSource, evmChainID int64, addr common.Address) error) (err error) { - return o.Transaction(ctx, func(orm *DbORM) error { +func (o *DSORM) DeleteForwarder(ctx context.Context, id int64, cleanup func(tx sqlutil.DataSource, evmChainID int64, addr common.Address) error) (err error) { + return o.Transact(ctx, func(orm *DSORM) error { var dest struct { EvmChainId int64 Address common.Address } - err := orm.db.GetContext(ctx, &dest, `SELECT evm_chain_id, address FROM evm.forwarders WHERE id = $1`, id) + err := orm.ds.GetContext(ctx, &dest, `SELECT evm_chain_id, address FROM evm.forwarders WHERE id = $1`, id) if err != nil { return err } if cleanup != nil { - if err = cleanup(orm.db, dest.EvmChainId, dest.Address); err != nil { + if err = cleanup(orm.ds, dest.EvmChainId, dest.Address); err != nil { return err } } - result, err := orm.db.ExecContext(ctx, `DELETE FROM evm.forwarders WHERE id = $1`, id) + result, err := orm.ds.ExecContext(ctx, `DELETE FROM evm.forwarders WHERE id = $1`, id) // If the forwarder wasn't found, we still want to delete the filter. // In that case, the transaction must return nil, even though DeleteForwarder // will return sql.ErrNoRows @@ -82,27 +82,27 @@ func (o *DbORM) DeleteForwarder(ctx context.Context, id int64, cleanup func(tx s } // FindForwarders returns all forwarder addresses from offset up until limit. -func (o *DbORM) FindForwarders(ctx context.Context, offset, limit int) (fwds []Forwarder, count int, err error) { +func (o *DSORM) FindForwarders(ctx context.Context, offset, limit int) (fwds []Forwarder, count int, err error) { sql := `SELECT count(*) FROM evm.forwarders` - if err = o.db.GetContext(ctx, &count, sql); err != nil { + if err = o.ds.GetContext(ctx, &count, sql); err != nil { return } sql = `SELECT * FROM evm.forwarders ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` - if err = o.db.SelectContext(ctx, &fwds, sql, limit, offset); err != nil { + if err = o.ds.SelectContext(ctx, &fwds, sql, limit, offset); err != nil { return } return } // FindForwardersByChain returns all forwarder addresses for a chain. -func (o *DbORM) FindForwardersByChain(ctx context.Context, evmChainId big.Big) (fwds []Forwarder, err error) { +func (o *DSORM) FindForwardersByChain(ctx context.Context, evmChainId big.Big) (fwds []Forwarder, err error) { sql := `SELECT * FROM evm.forwarders where evm_chain_id = $1 ORDER BY created_at DESC, id DESC` - err = o.db.SelectContext(ctx, &fwds, sql, evmChainId) + err = o.ds.SelectContext(ctx, &fwds, sql, evmChainId) return } -func (o *DbORM) FindForwardersInListByChain(ctx context.Context, evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) { +func (o *DSORM) FindForwardersInListByChain(ctx context.Context, evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) { var fwdrs []Forwarder arg := map[string]interface{}{ @@ -127,8 +127,8 @@ func (o *DbORM) FindForwardersInListByChain(ctx context.Context, evmChainId big. return nil, pkgerrors.Wrap(err, "Failed to run sqlx.IN on query") } - query = o.db.Rebind(query) - err = o.db.SelectContext(ctx, &fwdrs, query, args...) + query = o.ds.Rebind(query) + err = o.ds.SelectContext(ctx, &fwdrs, query, args...) if err != nil { return nil, pkgerrors.Wrap(err, "Failed to execute query") diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 40366c5b998..0cd4bbcdd0b 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -3,14 +3,10 @@ package gas import ( "context" "fmt" - "math" - "math/big" "slices" "sync" "time" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -19,7 +15,7 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" ) type ArbConfig interface { @@ -28,11 +24,6 @@ type ArbConfig interface { BumpMin() *assets.Wei } -//go:generate mockery --quiet --name ethClient --output ./mocks/ --case=underscore --structname ETHClient -type ethClient interface { - CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) -} - // arbitrumEstimator is an Estimator which extends SuggestedPriceEstimator to use getPricesInArbGas() for gas limit estimation. type arbitrumEstimator struct { services.StateMachine @@ -40,7 +31,6 @@ type arbitrumEstimator struct { EvmEstimator // *SuggestedPriceEstimator - client ethClient pollPeriod time.Duration logger logger.Logger @@ -52,20 +42,23 @@ type arbitrumEstimator struct { chInitialised chan struct{} chStop services.StopChan chDone chan struct{} + + l1Oracle rollups.ArbL1GasOracle } -func NewArbitrumEstimator(lggr logger.Logger, cfg ArbConfig, rpcClient rpcClient, ethClient ethClient) EvmEstimator { +func NewArbitrumEstimator(lggr logger.Logger, cfg ArbConfig, ethClient feeEstimatorClient, l1Oracle rollups.ArbL1GasOracle) EvmEstimator { lggr = logger.Named(lggr, "ArbitrumEstimator") + return &arbitrumEstimator{ cfg: cfg, - EvmEstimator: NewSuggestedPriceEstimator(lggr, rpcClient, cfg), - client: ethClient, + EvmEstimator: NewSuggestedPriceEstimator(lggr, ethClient, cfg, l1Oracle), pollPeriod: 10 * time.Second, logger: lggr, chForceRefetch: make(chan (chan struct{})), chInitialised: make(chan struct{}), chStop: make(chan struct{}), chDone: make(chan struct{}), + l1Oracle: l1Oracle, } } @@ -196,7 +189,7 @@ func (a *arbitrumEstimator) run() { func (a *arbitrumEstimator) refreshPricesInArbGas() (t *time.Timer) { t = time.NewTimer(utils.WithJitter(a.pollPeriod)) - perL2Tx, perL1CalldataUnit, err := a.callGetPricesInArbGas() + perL2Tx, perL1CalldataUnit, err := a.l1Oracle.GetPricesInArbGas() if err != nil { a.logger.Warnw("Failed to refresh prices", "err", err) return @@ -210,54 +203,3 @@ func (a *arbitrumEstimator) refreshPricesInArbGas() (t *time.Timer) { a.getPricesInArbGasMu.Unlock() return } - -const ( - // ArbGasInfoAddress is the address of the "Precompiled contract that exists in every Arbitrum chain." - // https://github.com/OffchainLabs/nitro/blob/f7645453cfc77bf3e3644ea1ac031eff629df325/contracts/src/precompiles/ArbGasInfo.sol - ArbGasInfoAddress = "0x000000000000000000000000000000000000006C" - // ArbGasInfo_getPricesInArbGas is the a hex encoded call to: - // `function getPricesInArbGas() external view returns (uint256, uint256, uint256);` - ArbGasInfo_getPricesInArbGas = "02199f34" -) - -// callGetPricesInArbGas calls ArbGasInfo.getPricesInArbGas() on the precompile contract ArbGasInfoAddress. -// -// @return (per L2 tx, per L1 calldata unit, per storage allocation) -// function getPricesInArbGas() external view returns (uint256, uint256, uint256); -// -// https://github.com/OffchainLabs/nitro/blob/f7645453cfc77bf3e3644ea1ac031eff629df325/contracts/src/precompiles/ArbGasInfo.sol#L69 -func (a *arbitrumEstimator) callGetPricesInArbGas() (perL2Tx uint32, perL1CalldataUnit uint32, err error) { - ctx, cancel := a.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) - defer cancel() - - precompile := common.HexToAddress(ArbGasInfoAddress) - b, err := a.client.CallContract(ctx, ethereum.CallMsg{ - To: &precompile, - Data: common.Hex2Bytes(ArbGasInfo_getPricesInArbGas), - }, big.NewInt(-1)) - if err != nil { - return 0, 0, err - } - - if len(b) != 3*32 { // returns (uint256, uint256, uint256); - err = fmt.Errorf("return data length (%d) different than expected (%d)", len(b), 3*32) - return - } - bPerL2Tx := new(big.Int).SetBytes(b[:32]) - bPerL1CalldataUnit := new(big.Int).SetBytes(b[32:64]) - // ignore perStorageAllocation - if !bPerL2Tx.IsUint64() || !bPerL1CalldataUnit.IsUint64() { - err = fmt.Errorf("returned integers are not uint64 (%s, %s)", bPerL2Tx.String(), bPerL1CalldataUnit.String()) - return - } - - perL2TxU64 := bPerL2Tx.Uint64() - perL1CalldataUnitU64 := bPerL1CalldataUnit.Uint64() - if perL2TxU64 > math.MaxUint32 || perL1CalldataUnitU64 > math.MaxUint32 { - err = fmt.Errorf("returned integers are not uint32 (%d, %d)", perL2TxU64, perL1CalldataUnitU64) - return - } - perL2Tx = uint32(perL2TxU64) - perL1CalldataUnit = uint32(perL1CalldataUnitU64) - return -} diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 3c46b466e87..54d7fc333e3 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -52,9 +53,10 @@ func TestArbitrumEstimator(t *testing.T) { var bumpMin = assets.NewWei(big.NewInt(1)) t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) @@ -64,21 +66,22 @@ func TestArbitrumEstimator(t *testing.T) { zeros.Write(common.BigToHash(big.NewInt(0)).Bytes()) zeros.Write(common.BigToHash(big.NewInt(123455)).Bytes()) t.Run("calling GetLegacyGas on started estimator returns estimates", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - rpcClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, feeEstimatorClient, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) @@ -88,19 +91,20 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { - client := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) @@ -113,19 +117,20 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("gas price is lower than global max gas price", func(t *testing.T) { - ethClient := mocks.NewETHClient(t) - client := mocks.NewRPCClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(120) }) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) @@ -137,24 +142,26 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on unstarted arbitrum estimator returns error", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) assert.EqualError(t, err, "estimator is not started") }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) @@ -165,17 +172,19 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("calling GetDynamicFee always returns error", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) _, err := o.GetDynamicFee(testutils.Context(t), maxGasPrice) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) t.Run("calling BumpDynamicFee always returns error", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) fee := gas.DynamicFee{ FeeCap: assets.NewWeiI(42), TipCap: assets.NewWeiI(5), @@ -185,9 +194,10 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("limit computes", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - rpcClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) @@ -201,15 +211,15 @@ func TestArbitrumEstimator(t *testing.T) { b.Write(common.BigToHash(big.NewInt(perL2Tx)).Bytes()) b.Write(common.BigToHash(big.NewInt(perL1Calldata)).Bytes()) b.Write(common.BigToHash(big.NewInt(123455)).Bytes()) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, feeEstimatorClient, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) @@ -220,9 +230,10 @@ func TestArbitrumEstimator(t *testing.T) { }) t.Run("limit exceeds max", func(t *testing.T) { - rpcClient := mocks.NewRPCClient(t) - ethClient := mocks.NewETHClient(t) - rpcClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) @@ -235,15 +246,15 @@ func TestArbitrumEstimator(t *testing.T) { b.Write(common.BigToHash(big.NewInt(perL2Tx)).Bytes()) b.Write(common.BigToHash(big.NewInt(perL1Calldata)).Bytes()) b.Write(common.BigToHash(big.NewInt(123455)).Bytes()) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - assert.Equal(t, gas.ArbGasInfoAddress, callMsg.To.String()) - assert.Equal(t, gas.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) + assert.Equal(t, rollups.ArbGasInfoAddress, callMsg.To.String()) + assert.Equal(t, rollups.ArbGasInfo_getPricesInArbGas, fmt.Sprintf("%x", callMsg.Data)) assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(b.Bytes(), nil) - o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, rpcClient, ethClient) + o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit, bumpPercent: bumpPercent, bumpMin: bumpMin}, feeEstimatorClient, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.Error(t, err, "expected error but got (%s, %d)", gasPrice, chainSpecificGasLimit) diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 5fb9c5d7173..8b8c626f725 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -24,7 +24,7 @@ import ( commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -97,7 +97,7 @@ type estimatorGasEstimatorConfig interface { //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore type BlockHistoryEstimator struct { services.StateMachine - ethClient evmclient.Client + ethClient feeEstimatorClient chainID big.Int config chainConfig eConfig estimatorGasEstimatorConfig @@ -120,13 +120,16 @@ type BlockHistoryEstimator struct { initialFetch atomic.Bool logger logger.SugaredLogger + + l1Oracle rollups.L1Oracle } // NewBlockHistoryEstimator returns a new BlockHistoryEstimator that listens // for new heads and updates the base gas price dynamically based on the // configured percentile of gas prices in that block -func NewBlockHistoryEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg chainConfig, eCfg estimatorGasEstimatorConfig, bhCfg BlockHistoryConfig, chainID big.Int) EvmEstimator { +func NewBlockHistoryEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg chainConfig, eCfg estimatorGasEstimatorConfig, bhCfg BlockHistoryConfig, chainID big.Int, l1Oracle rollups.L1Oracle) EvmEstimator { ctx, cancel := context.WithCancel(context.Background()) + b := &BlockHistoryEstimator{ ethClient: ethClient, chainID: chainID, @@ -141,6 +144,7 @@ func NewBlockHistoryEstimator(lggr logger.Logger, ethClient evmclient.Client, cf ctx: ctx, ctxCancel: cancel, logger: logger.Sugared(logger.Named(lggr, "BlockHistoryEstimator")), + l1Oracle: l1Oracle, } return b @@ -230,6 +234,10 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { }) } +func (b *BlockHistoryEstimator) L1Oracle() rollups.L1Oracle { + return b.l1Oracle +} + func (b *BlockHistoryEstimator) Close() error { return b.StopOnce("BlockHistoryEstimator", func() error { b.ctxCancel() diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index 5260a22bff3..941b60545ba 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -24,6 +24,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" + rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -42,12 +44,12 @@ func newBlockHistoryConfig() *gas.MockBlockHistoryConfig { return c } -func newBlockHistoryEstimatorWithChainID(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig, cid big.Int) gas.EvmEstimator { - return gas.NewBlockHistoryEstimator(logger.Test(t), c, cfg, gCfg, bhCfg, cid) +func newBlockHistoryEstimatorWithChainID(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig, cid big.Int, l1Oracle rollups.L1Oracle) gas.EvmEstimator { + return gas.NewBlockHistoryEstimator(logger.Test(t), c, cfg, gCfg, bhCfg, cid, l1Oracle) } -func newBlockHistoryEstimator(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig) *gas.BlockHistoryEstimator { - iface := newBlockHistoryEstimatorWithChainID(t, c, cfg, gCfg, bhCfg, cltest.FixtureChainID) +func newBlockHistoryEstimator(t *testing.T, c evmclient.Client, cfg gas.Config, gCfg gas.GasEstimatorConfig, bhCfg gas.BlockHistoryConfig, l1Oracle rollups.L1Oracle) *gas.BlockHistoryEstimator { + iface := newBlockHistoryEstimatorWithChainID(t, c, cfg, gCfg, bhCfg, cltest.FixtureChainID, l1Oracle) return gas.BlockHistoryEstimatorFromInterface(iface) } @@ -77,8 +79,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("loads initial state", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -121,8 +124,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { cfg2 := gas.NewMockConfig() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg2, geCfg2, bhCfg2) + bhe := newBlockHistoryEstimator(t, ethClient, cfg2, geCfg2, bhCfg2, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -154,8 +158,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("boots even if initial batch call returns nothing", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -172,8 +177,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("starts anyway if fetching latest head fails", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, pkgerrors.New("something exploded")) @@ -193,8 +199,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("starts anyway if fetching first fetch fails, but errors on estimation", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -216,8 +223,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("returns error if main context is cancelled", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -232,8 +240,9 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("starts anyway even if the fetch context is cancelled due to taking longer than the MaxStartTime", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -261,8 +270,9 @@ func TestBlockHistoryEstimator_OnNewLongestChain(t *testing.T) { bhCfg := newBlockHistoryConfig() geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) assert.Nil(t, gas.GetLatestBaseFee(bhe)) @@ -284,6 +294,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("with history size of 0, errors", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -295,7 +307,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) head := cltest.Head(42) err := bhe.FetchBlocks(testutils.Context(t), head) @@ -305,6 +317,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("with current block height less than block delay does nothing", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() var blockDelay uint16 = 3 @@ -315,7 +329,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) for i := -1; i < 3; i++ { head := cltest.Head(i) @@ -327,6 +341,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("with error retrieving blocks returns error", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() var blockDelay uint16 = 3 @@ -338,7 +354,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(pkgerrors.New("something exploded")) @@ -349,6 +365,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("batch fetches heads and transactions and sets them on the block history estimator instance", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() var blockDelay uint16 @@ -362,7 +380,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b41 := evmtypes.Block{ Number: 41, @@ -443,6 +461,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("does not refetch blocks below EVM.FinalityDepth", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() var blockDelay uint16 @@ -455,7 +475,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b0 := evmtypes.Block{ Number: 0, @@ -506,6 +526,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("replaces blocks on re-org within EVM.FinalityDepth", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() var blockDelay uint16 @@ -518,7 +540,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b0 := evmtypes.Block{ Number: 0, @@ -577,6 +599,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("uses locally cached blocks if they are in the chain", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() var blockDelay uint16 var historySize uint16 = 3 @@ -589,7 +613,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b0 := evmtypes.Block{ Number: 0, @@ -634,6 +658,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { t.Run("fetches max(BlockHistoryEstimatorCheckInclusionBlocks, BlockHistoryEstimatorBlockHistorySize)", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() var blockDelay uint16 var historySize uint16 = 1 @@ -648,7 +674,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b42 := evmtypes.Block{ Number: 42, @@ -686,6 +712,8 @@ func TestBlockHistoryEstimator_FetchBlocksAndRecalculate_NoEIP1559(t *testing.T) t.Parallel() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() bhCfg.BlockDelayF = uint16(0) @@ -698,7 +726,7 @@ func TestBlockHistoryEstimator_FetchBlocksAndRecalculate_NoEIP1559(t *testing.T) geCfg.PriceMaxF = assets.NewWeiI(1000) geCfg.PriceMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1 := evmtypes.Block{ Number: 1, @@ -744,6 +772,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("does not crash or set gas price to zero if there are no transactions", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -753,7 +782,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{} gas.SetRollingBlockHistory(bhe, blocks) @@ -770,6 +799,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("sets gas price to EVM.GasEstimator.PriceMax if the calculation would otherwise exceed it", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -780,7 +811,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = minGasPrice - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -805,6 +836,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("sets gas price to EVM.GasEstimator.PriceMin if the calculation would otherwise fall below it", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -815,7 +848,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = minGasPrice - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -840,6 +873,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("ignores any transaction with a zero gas limit", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -850,7 +885,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = minGasPrice - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() b2Hash := utils.NewHash() @@ -887,6 +922,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("takes into account zero priced transactions if chain is not Gnosis", func(t *testing.T) { // Because everyone loves free gas! ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -897,7 +934,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() @@ -920,6 +957,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("ignores zero priced transactions only on Gnosis", func(t *testing.T) { ethClient := evmtest.NewEthClientMock(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -930,7 +969,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = assets.NewWeiI(11) // Has to be set as Gnosis will only ignore transactions below this price - ibhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + ibhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) bhe := gas.BlockHistoryEstimatorFromInterface(ibhe) b1Hash := utils.NewHash() @@ -964,6 +1003,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { // Seems unlikely we will ever experience gas prices > 9 Petawei on mainnet (praying to the eth Gods 🙏) // But other chains could easily use a different base of account ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -976,7 +1017,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = reasonablyHugeGasPrice geCfg.PriceMinF = assets.NewWeiI(10) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) unreasonablyHugeGasPrice := assets.NewWeiI(1000000).Mul(big.NewInt(math.MaxInt64)) @@ -1011,6 +1052,8 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { t.Run("doesn't panic if gas price is nil (although I'm still unsure how this can happen)", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1021,7 +1064,7 @@ func TestBlockHistoryEstimator_Recalculate_NoEIP1559(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = assets.NewWeiI(100) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() @@ -1057,6 +1100,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("does not crash or set gas price to zero if there are no transactions", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1066,7 +1110,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{} gas.SetRollingBlockHistory(bhe, blocks) @@ -1095,6 +1139,8 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("does not set tip higher than EVM.GasEstimator.PriceMax", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1106,7 +1152,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg.PriceMinF = assets.NewWeiI(0) geCfg.TipCapMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -1133,6 +1179,8 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("sets tip cap to EVM.GasEstimator.TipCapMin if the calculation would otherwise fall below it", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1144,7 +1192,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg.PriceMinF = assets.NewWeiI(0) geCfg.TipCapMinF = assets.NewWeiI(10) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -1171,6 +1219,8 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("ignores any transaction with a zero gas limit", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1182,7 +1232,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg.PriceMinF = assets.NewWeiI(0) geCfg.TipCapMinF = assets.NewWeiI(10) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() b2Hash := utils.NewHash() @@ -1219,6 +1269,8 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("respects minimum gas tip cap", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1230,7 +1282,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg.PriceMinF = assets.NewWeiI(0) geCfg.TipCapMinF = assets.NewWeiI(1) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() @@ -1255,6 +1307,8 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { t.Run("allows to set zero tip cap if minimum allows it", func(t *testing.T) { // Because everyone loves *cheap* gas! ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1266,7 +1320,7 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { geCfg.PriceMinF = assets.NewWeiI(0) geCfg.TipCapMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) b1Hash := utils.NewHash() @@ -1291,12 +1345,14 @@ func TestBlockHistoryEstimator_Recalculate_EIP1559(t *testing.T) { func TestBlockHistoryEstimator_IsUsable(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) block := evmtypes.Block{ Number: 0, Hash: utils.NewHash(), @@ -1373,13 +1429,15 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) block := evmtypes.Block{ Number: 0, @@ -1433,13 +1491,15 @@ func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { func TestBlockHistoryEstimator_EffectiveGasPrice(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) block := evmtypes.Block{ Number: 0, @@ -1772,6 +1832,7 @@ func TestBlockHistoryEstimator_EIP1559Block_Unmarshal(t *testing.T) { func TestBlockHistoryEstimator_GetLegacyGas(t *testing.T) { t.Parallel() + l1Oracle := rollupMocks.NewL1Oracle(t) cfg := gas.NewMockConfig() bhCfg := newBlockHistoryConfig() @@ -1786,7 +1847,7 @@ func TestBlockHistoryEstimator_GetLegacyGas(t *testing.T) { geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -1830,7 +1891,7 @@ func TestBlockHistoryEstimator_GetLegacyGas(t *testing.T) { geCfg.EIP1559DynamicFeesF = false - bhe = newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe = newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) gas.SetRollingBlockHistory(bhe, blocks) bhe.Recalculate(cltest.Head(1)) gas.SimulateStart(t, bhe) @@ -1867,7 +1928,9 @@ func TestBlockHistoryEstimator_UseDefaultPriceAsFallback(t *testing.T) { geCfg.PriceDefaultF = assets.NewWeiI(100) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + l1Oracle := rollupMocks.NewL1Oracle(t) + + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: nil} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -1918,7 +1981,9 @@ func TestBlockHistoryEstimator_UseDefaultPriceAsFallback(t *testing.T) { geCfg.BumpThresholdF = uint64(1) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + l1Oracle := rollupMocks.NewL1Oracle(t) + + bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg, l1Oracle) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(40)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) @@ -1967,7 +2032,9 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { geCfg.TipCapMinF = assets.NewWeiI(0) geCfg.PriceMinF = assets.NewWeiI(0) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + l1Oracle := rollupMocks.NewL1Oracle(t) + + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) blocks := []evmtypes.Block{ { @@ -2065,9 +2132,10 @@ func TestBlockHistoryEstimator_CheckConnectivity(t *testing.T) { lggr, obs := logger.TestObserved(t, zapcore.DebugLevel) geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false + l1Oracle := rollupMocks.NewL1Oracle(t) bhe := gas.BlockHistoryEstimatorFromInterface( - gas.NewBlockHistoryEstimator(lggr, nil, cfg, geCfg, bhCfg, *testutils.NewRandomEVMChainID()), + gas.NewBlockHistoryEstimator(lggr, nil, cfg, geCfg, bhCfg, *testutils.NewRandomEVMChainID(), l1Oracle), ) attempts := []gas.EvmPriorAttempt{ @@ -2365,8 +2433,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) b1 := evmtypes.Block{ Number: 1, @@ -2394,8 +2463,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) t.Run("ignores nil current gas price", func(t *testing.T) { gasPrice, gasLimit, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) @@ -2475,8 +2545,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) b1 := evmtypes.Block{ BaseFeePerGas: assets.NewWeiI(1), @@ -2508,8 +2579,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice geCfg.TipCapDefaultF = assets.NewWeiI(52) + l1Oracle := rollupMocks.NewL1Oracle(t) - bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg, l1Oracle) t.Run("when current tip cap is nil", func(t *testing.T) { originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} diff --git a/core/chains/evm/gas/cmd/arbgas/main.go b/core/chains/evm/gas/cmd/arbgas/main.go deleted file mode 100644 index dc107a50b52..00000000000 --- a/core/chains/evm/gas/cmd/arbgas/main.go +++ /dev/null @@ -1,85 +0,0 @@ -// arbgas takes a single URL argument and prints the result of three GetLegacyGas calls to the Arbitrum gas estimator. -package main - -import ( - "context" - "fmt" - "log" - "os" - - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" -) - -func main() { - if l := len(os.Args); l != 2 { - log.Fatal("Expected one URL argument but got", l-1) - } - url := os.Args[1] - lggr, err := logger.New() - if err != nil { - log.Fatal("Failed to create logger:", err) - } - - ctx := context.Background() - withEstimator(ctx, logger.Sugared(lggr), url, func(e gas.EvmEstimator) { - printGetLegacyGas(ctx, e, make([]byte, 10), 500_000, assets.GWei(1)) - printGetLegacyGas(ctx, e, make([]byte, 10), 500_000, assets.GWei(1), feetypes.OptForceRefetch) - printGetLegacyGas(ctx, e, make([]byte, 10), max, assets.GWei(1)) - }) -} - -func printGetLegacyGas(ctx context.Context, e gas.EvmEstimator, calldata []byte, l2GasLimit uint64, maxGasPrice *assets.Wei, opts ...feetypes.Opt) { - price, limit, err := e.GetLegacyGas(ctx, calldata, l2GasLimit, maxGasPrice, opts...) - if err != nil { - log.Println("failed to get legacy gas:", err) - return - } - fmt.Println("Price:", price) - fmt.Println("Limit:", limit) -} - -const max = 50_000_000 - -func withEstimator(ctx context.Context, lggr logger.SugaredLogger, url string, f func(e gas.EvmEstimator)) { - rc, err := rpc.Dial(url) - if err != nil { - log.Fatal(err) - } - ec := ethclient.NewClient(rc) - e := gas.NewArbitrumEstimator(lggr, &config{max: max}, rc, ec) - ctx, cancel := context.WithCancel(ctx) - defer cancel() - err = e.Start(ctx) - if err != nil { - log.Fatal(err) - } - defer lggr.ErrorIfFn(e.Close, "Error closing ArbitrumEstimator") - - f(e) -} - -var _ gas.ArbConfig = &config{} - -type config struct { - max uint64 - bumpPercent uint16 - bumpMin *assets.Wei -} - -func (c *config) LimitMax() uint64 { - return c.max -} - -func (c *config) BumpPercent() uint16 { - return c.bumpPercent -} - -func (c *config) BumpMin() *assets.Wei { - return c.bumpMin -} diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index fc65413d375..f4749b093a1 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -9,6 +9,7 @@ import ( commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -18,6 +19,7 @@ type fixedPriceEstimator struct { config fixedPriceEstimatorConfig bhConfig fixedPriceEstimatorBlockHistoryConfig lggr logger.SugaredLogger + l1Oracle rollups.L1Oracle } type bumpConfig interface { LimitMultiplier() float32 @@ -43,8 +45,8 @@ type fixedPriceEstimatorBlockHistoryConfig interface { // NewFixedPriceEstimator returns a new "FixedPrice" estimator which will // always use the config default values for gas prices and limits -func NewFixedPriceEstimator(cfg fixedPriceEstimatorConfig, bhCfg fixedPriceEstimatorBlockHistoryConfig, lggr logger.Logger) EvmEstimator { - return &fixedPriceEstimator{cfg, bhCfg, logger.Sugared(logger.Named(lggr, "FixedPriceEstimator"))} +func NewFixedPriceEstimator(cfg fixedPriceEstimatorConfig, ethClient feeEstimatorClient, bhCfg fixedPriceEstimatorBlockHistoryConfig, lggr logger.Logger, l1Oracle rollups.L1Oracle) EvmEstimator { + return &fixedPriceEstimator{cfg, bhCfg, logger.Sugared(logger.Named(lggr, "FixedPriceEstimator")), l1Oracle} } func (f *fixedPriceEstimator) Start(context.Context) error { @@ -128,6 +130,10 @@ func (f *fixedPriceEstimator) BumpDynamicFee( ) } +func (f *fixedPriceEstimator) L1Oracle() rollups.L1Oracle { + return f.l1Oracle +} + func (f *fixedPriceEstimator) Name() string { return f.lggr.Name() } func (f *fixedPriceEstimator) Ready() error { return nil } func (f *fixedPriceEstimator) HealthReport() map[string]error { return map[string]error{} } diff --git a/core/chains/evm/gas/fixed_price_estimator_test.go b/core/chains/evm/gas/fixed_price_estimator_test.go index c31bd41aeee..9c68f9d2fbc 100644 --- a/core/chains/evm/gas/fixed_price_estimator_test.go +++ b/core/chains/evm/gas/fixed_price_estimator_test.go @@ -9,6 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -26,7 +27,9 @@ func Test_FixedPriceEstimator(t *testing.T) { t.Run("GetLegacyGas returns EvmGasPriceDefault from config", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) + l1Oracle := rollupMocks.NewL1Oracle(t) + + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, logger.Test(t), l1Oracle) config.PriceDefaultF = assets.NewWeiI(42) config.PriceMaxF = maxGasPrice @@ -41,7 +44,9 @@ func Test_FixedPriceEstimator(t *testing.T) { config := &gas.MockGasEstimatorConfig{} config.PriceDefaultF = assets.NewWeiI(42) config.PriceMaxF = assets.NewWeiI(35) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) + l1Oracle := rollupMocks.NewL1Oracle(t) + + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, logger.Test(t), l1Oracle) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) @@ -53,8 +58,9 @@ func Test_FixedPriceEstimator(t *testing.T) { config := &gas.MockGasEstimatorConfig{} config.PriceDefaultF = assets.NewWeiI(42) config.PriceMaxF = assets.NewWeiI(20) + l1Oracle := rollupMocks.NewL1Oracle(t) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, logger.Test(t), l1Oracle) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) assert.Equal(t, 100000, int(gasLimit)) @@ -67,9 +73,10 @@ func Test_FixedPriceEstimator(t *testing.T) { config.PriceMaxF = maxGasPrice config.BumpPercentF = uint16(10) config.BumpMinF = assets.NewWeiI(150) + l1Oracle := rollupMocks.NewL1Oracle(t) lggr := logger.TestSugared(t) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, lggr, l1Oracle) gasPrice, gasLimit, err := f.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) @@ -87,9 +94,10 @@ func Test_FixedPriceEstimator(t *testing.T) { config.TipCapDefaultF = assets.NewWeiI(52) config.FeeCapDefaultF = assets.NewWeiI(100) config.BumpThresholdF = uint64(3) + l1Oracle := rollupMocks.NewL1Oracle(t) lggr := logger.Test(t) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, lggr, l1Oracle) fee, err := f.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) @@ -120,9 +128,10 @@ func Test_FixedPriceEstimator(t *testing.T) { config.TipCapDefaultF = assets.NewWeiI(52) config.BumpMinF = assets.NewWeiI(150) config.BumpPercentF = uint16(10) + l1Oracle := rollupMocks.NewL1Oracle(t) lggr := logger.TestSugared(t) - f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) + f := gas.NewFixedPriceEstimator(config, nil, &blockHistoryConfig{}, lggr, l1Oracle) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} fee, err := f.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index 4a7b6f4d7eb..a3b6b8ee491 100644 --- a/core/chains/evm/gas/mocks/config.go +++ b/core/chains/evm/gas/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/eth_client.go b/core/chains/evm/gas/mocks/eth_client.go index bb0784f8515..a8cc5afa8d9 100644 --- a/core/chains/evm/gas/mocks/eth_client.go +++ b/core/chains/evm/gas/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index a0b6fa62432..1213a71742d 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -13,6 +13,8 @@ import ( mock "github.com/stretchr/testify/mock" + rollups "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" + types "github.com/smartcontractkit/chainlink/v2/common/fee/types" ) @@ -196,6 +198,26 @@ func (_m *EvmEstimator) HealthReport() map[string]error { return r0 } +// L1Oracle provides a mock function with given fields: +func (_m *EvmEstimator) L1Oracle() rollups.L1Oracle { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for L1Oracle") + } + + var r0 rollups.L1Oracle + if rf, ok := ret.Get(0).(func() rollups.L1Oracle); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rollups.L1Oracle) + } + } + + return r0 +} + // Name provides a mock function with given fields: func (_m *EvmEstimator) Name() string { ret := _m.Called() diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index 7ebde8bc0fd..5179a2560d0 100644 --- a/core/chains/evm/gas/mocks/evm_fee_estimator.go +++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/fee_estimator_client.go b/core/chains/evm/gas/mocks/fee_estimator_client.go new file mode 100644 index 00000000000..d81120e2ed4 --- /dev/null +++ b/core/chains/evm/gas/mocks/fee_estimator_client.go @@ -0,0 +1,154 @@ +// Code generated by mockery v2.42.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + big "math/big" + + ethereum "github.com/ethereum/go-ethereum" + + mock "github.com/stretchr/testify/mock" + + rpc "github.com/ethereum/go-ethereum/rpc" + + types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" +) + +// FeeEstimatorClient is an autogenerated mock type for the feeEstimatorClient type +type FeeEstimatorClient struct { + mock.Mock +} + +// BatchCallContext provides a mock function with given fields: ctx, b +func (_m *FeeEstimatorClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { + ret := _m.Called(ctx, b) + + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { + r0 = rf(ctx, b) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CallContext provides a mock function with given fields: ctx, result, method, args +func (_m *FeeEstimatorClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + var _ca []interface{} + _ca = append(_ca, ctx, result, method) + _ca = append(_ca, args...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CallContext") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { + r0 = rf(ctx, result, method, args...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CallContract provides a mock function with given fields: ctx, msg, blockNumber +func (_m *FeeEstimatorClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, msg, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { + return rf(ctx, msg, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) []byte); ok { + r0 = rf(ctx, msg, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg, *big.Int) error); ok { + r1 = rf(ctx, msg, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ConfiguredChainID provides a mock function with given fields: +func (_m *FeeEstimatorClient) ConfiguredChainID() *big.Int { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + + var r0 *big.Int + if rf, ok := ret.Get(0).(func() *big.Int); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + return r0 +} + +// HeadByNumber provides a mock function with given fields: ctx, n +func (_m *FeeEstimatorClient) HeadByNumber(ctx context.Context, n *big.Int) (*types.Head, error) { + ret := _m.Called(ctx, n) + + if len(ret) == 0 { + panic("no return value specified for HeadByNumber") + } + + var r0 *types.Head + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Head, error)); ok { + return rf(ctx, n) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *types.Head); ok { + r0 = rf(ctx, n) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Head) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, n) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewFeeEstimatorClient creates a new instance of FeeEstimatorClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFeeEstimatorClient(t interface { + mock.TestingT + Cleanup(func()) +}) *FeeEstimatorClient { + mock := &FeeEstimatorClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/chains/evm/gas/mocks/rpc_client.go b/core/chains/evm/gas/mocks/rpc_client.go index d1262665f66..826fd66c463 100644 --- a/core/chains/evm/gas/mocks/rpc_client.go +++ b/core/chains/evm/gas/mocks/rpc_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 04673d5a622..c50e19373f1 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -5,8 +5,10 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -18,7 +20,6 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" @@ -41,8 +42,17 @@ type EvmFeeEstimator interface { GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (*big.Int, error) } +//go:generate mockery --quiet --name feeEstimatorClient --output ./mocks/ --case=underscore --structname FeeEstimatorClient +type feeEstimatorClient interface { + CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) + BatchCallContext(ctx context.Context, b []rpc.BatchElem) error + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + ConfiguredChainID() *big.Int + HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error) +} + // NewEstimator returns the estimator for a given config -func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, geCfg evmconfig.GasEstimator) EvmFeeEstimator { +func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config, geCfg evmconfig.GasEstimator) EvmFeeEstimator { bh := geCfg.BlockHistory() s := geCfg.Mode() lggr.Infow(fmt.Sprintf("Initializing EVM gas estimator in mode: %s", s), @@ -75,27 +85,27 @@ func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, ge switch s { case "Arbitrum": newEstimator = func(l logger.Logger) EvmEstimator { - return NewArbitrumEstimator(lggr, geCfg, ethClient, ethClient) + return NewArbitrumEstimator(lggr, geCfg, ethClient, rollups.NewArbitrumL1GasOracle(lggr, ethClient)) } case "BlockHistory": newEstimator = func(l logger.Logger) EvmEstimator { - return NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()) + return NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID(), l1Oracle) } case "FixedPrice": newEstimator = func(l logger.Logger) EvmEstimator { - return NewFixedPriceEstimator(geCfg, bh, lggr) + return NewFixedPriceEstimator(geCfg, ethClient, bh, lggr, l1Oracle) } case "L2Suggested", "SuggestedPrice": newEstimator = func(l logger.Logger) EvmEstimator { - return NewSuggestedPriceEstimator(lggr, ethClient, geCfg) + return NewSuggestedPriceEstimator(lggr, ethClient, geCfg, l1Oracle) } default: lggr.Warnf("GasEstimator: unrecognised mode '%s', falling back to FixedPriceEstimator", s) newEstimator = func(l logger.Logger) EvmEstimator { - return NewFixedPriceEstimator(geCfg, bh, lggr) + return NewFixedPriceEstimator(geCfg, ethClient, bh, lggr, l1Oracle) } } - return NewWrappedEvmEstimator(lggr, newEstimator, df, l1Oracle, geCfg) + return NewEvmFeeEstimator(lggr, newEstimator, df, geCfg) } // DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions @@ -138,6 +148,8 @@ type EvmEstimator interface { // - be sorted in order from highest price to lowest price // - all be of transaction type 0x2 BumpDynamicFee(ctx context.Context, original DynamicFee, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, err error) + + L1Oracle() rollups.L1Oracle } var _ feetypes.Fee = (*EvmFee)(nil) @@ -159,53 +171,53 @@ func (fee EvmFee) ValidDynamic() bool { return fee.DynamicFeeCap != nil && fee.DynamicTipCap != nil } -// WrappedEvmEstimator provides a struct that wraps the EVM specific dynamic and legacy estimators into one estimator that conforms to the generic FeeEstimator -type WrappedEvmEstimator struct { +// evmFeeEstimator provides a struct that wraps the EVM specific dynamic and legacy estimators into one estimator that conforms to the generic FeeEstimator +type evmFeeEstimator struct { services.StateMachine lggr logger.Logger EvmEstimator EIP1559Enabled bool - l1Oracle rollups.L1Oracle geCfg GasEstimatorConfig } -var _ EvmFeeEstimator = (*WrappedEvmEstimator)(nil) +var _ EvmFeeEstimator = (*evmFeeEstimator)(nil) -func NewWrappedEvmEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle, geCfg GasEstimatorConfig) EvmFeeEstimator { +func NewEvmFeeEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, geCfg GasEstimatorConfig) EvmFeeEstimator { lggr = logger.Named(lggr, "WrappedEvmEstimator") - return &WrappedEvmEstimator{ + return &evmFeeEstimator{ lggr: lggr, EvmEstimator: newEstimator(lggr), EIP1559Enabled: eip1559Enabled, - l1Oracle: l1Oracle, geCfg: geCfg, } } -func (e *WrappedEvmEstimator) Name() string { +func (e *evmFeeEstimator) Name() string { return e.lggr.Name() } -func (e *WrappedEvmEstimator) Start(ctx context.Context) error { +func (e *evmFeeEstimator) Start(ctx context.Context) error { return e.StartOnce(e.Name(), func() error { if err := e.EvmEstimator.Start(ctx); err != nil { return pkgerrors.Wrap(err, "failed to start EVMEstimator") } - if e.l1Oracle != nil { - if err := e.l1Oracle.Start(ctx); err != nil { + l1Oracle := e.L1Oracle() + if l1Oracle != nil { + if err := l1Oracle.Start(ctx); err != nil { return pkgerrors.Wrap(err, "failed to start L1Oracle") } } return nil }) } -func (e *WrappedEvmEstimator) Close() error { +func (e *evmFeeEstimator) Close() error { return e.StopOnce(e.Name(), func() error { var errEVM, errOracle error errEVM = pkgerrors.Wrap(e.EvmEstimator.Close(), "failed to stop EVMEstimator") - if e.l1Oracle != nil { - errOracle = pkgerrors.Wrap(e.l1Oracle.Close(), "failed to stop L1Oracle") + l1Oracle := e.L1Oracle() + if l1Oracle != nil { + errOracle = pkgerrors.Wrap(l1Oracle.Close(), "failed to stop L1Oracle") } if errEVM != nil { @@ -215,12 +227,13 @@ func (e *WrappedEvmEstimator) Close() error { }) } -func (e *WrappedEvmEstimator) Ready() error { +func (e *evmFeeEstimator) Ready() error { var errEVM, errOracle error errEVM = e.EvmEstimator.Ready() - if e.l1Oracle != nil { - errOracle = e.l1Oracle.Ready() + l1Oracle := e.L1Oracle() + if l1Oracle != nil { + errOracle = l1Oracle.Ready() } if errEVM != nil { @@ -229,21 +242,23 @@ func (e *WrappedEvmEstimator) Ready() error { return errOracle } -func (e *WrappedEvmEstimator) HealthReport() map[string]error { +func (e *evmFeeEstimator) HealthReport() map[string]error { report := map[string]error{e.Name(): e.Healthy()} services.CopyHealth(report, e.EvmEstimator.HealthReport()) - if e.l1Oracle != nil { - services.CopyHealth(report, e.l1Oracle.HealthReport()) + + l1Oracle := e.L1Oracle() + if l1Oracle != nil { + services.CopyHealth(report, l1Oracle.HealthReport()) } return report } -func (e *WrappedEvmEstimator) L1Oracle() rollups.L1Oracle { - return e.l1Oracle +func (e *evmFeeEstimator) L1Oracle() rollups.L1Oracle { + return e.EvmEstimator.L1Oracle() } -func (e *WrappedEvmEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee EvmFee, chainSpecificFeeLimit uint64, err error) { +func (e *evmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee EvmFee, chainSpecificFeeLimit uint64, err error) { // get dynamic fee if e.EIP1559Enabled { var dynamicFee DynamicFee @@ -267,7 +282,7 @@ func (e *WrappedEvmEstimator) GetFee(ctx context.Context, calldata []byte, feeLi return } -func (e *WrappedEvmEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (*big.Int, error) { +func (e *evmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (*big.Int, error) { fees, gasLimit, err := e.GetFee(ctx, calldata, feeLimit, maxFeePrice, opts...) if err != nil { return nil, err @@ -285,7 +300,7 @@ func (e *WrappedEvmEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, return amountWithFees, nil } -func (e *WrappedEvmEstimator) BumpFee(ctx context.Context, originalFee EvmFee, feeLimit uint64, maxFeePrice *assets.Wei, attempts []EvmPriorAttempt) (bumpedFee EvmFee, chainSpecificFeeLimit uint64, err error) { +func (e *evmFeeEstimator) BumpFee(ctx context.Context, originalFee EvmFee, feeLimit uint64, maxFeePrice *assets.Wei, attempts []EvmPriorAttempt) (bumpedFee EvmFee, chainSpecificFeeLimit uint64, err error) { // validate only 1 fee type is present if (!originalFee.ValidDynamic() && originalFee.Legacy == nil) || (originalFee.ValidDynamic() && originalFee.Legacy != nil) { err = pkgerrors.New("only one dynamic or legacy fee can be defined") diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index ec9542b4040..722beb8021a 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -10,9 +10,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -49,14 +51,24 @@ func TestWrappedEvmEstimator(t *testing.T) { // L1Oracle returns the correct L1Oracle interface t.Run("L1Oracle", func(t *testing.T) { lggr := logger.Test(t) + + evmEstimator := mocks.NewEvmEstimator(t) + evmEstimator.On("L1Oracle").Return(nil).Once() + + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } + // expect nil - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, false, nil, nil) + estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, nil) l1Oracle := estimator.L1Oracle() + assert.Nil(t, l1Oracle) // expect l1Oracle - oracle := rollupMocks.NewL1Oracle(t) - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, false, oracle, geCfg) + oracle := rollups.NewL1GasOracle(lggr, nil, config.ChainOptimismBedrock) + // cast oracle to L1Oracle interface + estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) + + evmEstimator.On("L1Oracle").Return(oracle).Once() l1Oracle = estimator.L1Oracle() assert.Equal(t, oracle, l1Oracle) }) @@ -66,7 +78,7 @@ func TestWrappedEvmEstimator(t *testing.T) { lggr := logger.Test(t) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg) fee, max, err := estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) @@ -76,7 +88,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg) fee, max, err = estimator.GetFee(ctx, nil, gasLimit, nil) require.NoError(t, err) assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) @@ -89,7 +101,7 @@ func TestWrappedEvmEstimator(t *testing.T) { t.Run("BumpFee", func(t *testing.T) { lggr := logger.Test(t) dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg) // expect legacy fee data fee, max, err := estimator.BumpFee(ctx, gas.EvmFee{Legacy: assets.NewWeiI(0)}, 0, nil, nil) @@ -127,7 +139,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg) total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee := new(big.Int).Mul(legacyFee.ToInt(), big.NewInt(int64(gasLimit))) @@ -136,7 +148,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg) total, err = estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee = new(big.Int).Mul(dynamicFee.FeeCap.ToInt(), big.NewInt(int64(gasLimit))) @@ -147,13 +159,12 @@ func TestWrappedEvmEstimator(t *testing.T) { t.Run("Name", func(t *testing.T) { lggr := logger.Test(t) - oracle := rollupMocks.NewL1Oracle(t) evmEstimator := mocks.NewEvmEstimator(t) evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Once() - estimator := gas.NewWrappedEvmEstimator(lggr, func(logger.Logger) gas.EvmEstimator { + estimator := gas.NewEvmFeeEstimator(lggr, func(logger.Logger) gas.EvmEstimator { return evmEstimator - }, false, oracle, geCfg) + }, false, geCfg) require.Equal(t, mockEstimatorName, estimator.Name()) require.Equal(t, mockEvmEstimatorName, evmEstimator.Name()) @@ -170,13 +181,17 @@ func TestWrappedEvmEstimator(t *testing.T) { oracle.On("Close").Return(nil).Once() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) + evmEstimator.On("L1Oracle", mock.Anything).Return(nil).Twice() + + estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) err := estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) + evmEstimator.On("L1Oracle", mock.Anything).Return(oracle).Twice() + + estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) err = estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() @@ -188,15 +203,16 @@ func TestWrappedEvmEstimator(t *testing.T) { evmEstimator := mocks.NewEvmEstimator(t) oracle := rollupMocks.NewL1Oracle(t) + evmEstimator.On("L1Oracle").Return(oracle).Twice() evmEstimator.On("Ready").Return(nil).Twice() - oracle.On("Ready").Return(nil).Once() + oracle.On("Ready").Return(nil).Twice() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) + estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) err := estimator.Ready() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) + estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) err = estimator.Ready() require.NoError(t, err) }) @@ -211,17 +227,21 @@ func TestWrappedEvmEstimator(t *testing.T) { oracleKey := "oracle" oracleError := pkgerrors.New("oracle error") + evmEstimator.On("L1Oracle").Return(nil).Once() evmEstimator.On("HealthReport").Return(map[string]error{evmEstimatorKey: evmEstimatorError}).Twice() + oracle.On("HealthReport").Return(map[string]error{oracleKey: oracleError}).Once() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) + estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) report := estimator.HealthReport() require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) require.Nil(t, report[oracleKey]) require.NotNil(t, report[mockEstimatorName]) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) + evmEstimator.On("L1Oracle").Return(oracle).Once() + + estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) report = estimator.HealthReport() require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) require.True(t, pkgerrors.Is(report[oracleKey], oracleError)) diff --git a/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go b/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go new file mode 100644 index 00000000000..d0b4c5808ad --- /dev/null +++ b/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go @@ -0,0 +1,300 @@ +package rollups + +import ( + "context" + "fmt" + "math" + "math/big" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + + gethtypes "github.com/ethereum/go-ethereum/core/types" + + "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" +) + +type ArbL1GasOracle interface { + L1Oracle + GetPricesInArbGas() (perL2Tx uint32, perL1CalldataUnit uint32, err error) +} + +// Reads L2-specific precompiles and caches the l1GasPrice set by the L2. +type arbitrumL1Oracle struct { + services.StateMachine + client l1OracleClient + pollPeriod time.Duration + logger logger.SugaredLogger + chainType config.ChainType + + l1GasPriceAddress string + gasPriceMethod string + l1GasPriceMethodAbi abi.ABI + l1GasPriceMu sync.RWMutex + l1GasPrice priceEntry + + l1GasCostAddress string + gasCostMethod string + l1GasCostMethodAbi abi.ABI + + chInitialised chan struct{} + chStop services.StopChan + chDone chan struct{} +} + +const ( + // ArbGasInfoAddress is the address of the "Precompiled contract that exists in every Arbitrum chain." + // https://github.com/OffchainLabs/nitro/blob/f7645453cfc77bf3e3644ea1ac031eff629df325/contracts/src/precompiles/ArbGasInfo.sol + ArbGasInfoAddress = "0x000000000000000000000000000000000000006C" + // ArbGasInfo_getL1BaseFeeEstimate is the a hex encoded call to: + // `function getL1BaseFeeEstimate() external view returns (uint256);` + ArbGasInfo_getL1BaseFeeEstimate = "getL1BaseFeeEstimate" + // NodeInterfaceAddress is the address of the precompiled contract that is only available through RPC + // https://github.com/OffchainLabs/nitro/blob/e815395d2e91fb17f4634cad72198f6de79c6e61/nodeInterface/NodeInterface.go#L37 + ArbNodeInterfaceAddress = "0x00000000000000000000000000000000000000C8" + // ArbGasInfo_getPricesInArbGas is the a hex encoded call to: + // `function gasEstimateL1Component(address to, bool contractCreation, bytes calldata data) external payable returns (uint64 gasEstimateForL1, uint256 baseFee, uint256 l1BaseFeeEstimate);` + ArbNodeInterface_gasEstimateL1Component = "gasEstimateL1Component" + // ArbGasInfo_getPricesInArbGas is the a hex encoded call to: + // `function getPricesInArbGas() external view returns (uint256, uint256, uint256);` + ArbGasInfo_getPricesInArbGas = "02199f34" +) + +func NewArbitrumL1GasOracle(lggr logger.Logger, ethClient l1OracleClient) *arbitrumL1Oracle { + var l1GasPriceAddress, gasPriceMethod, l1GasCostAddress, gasCostMethod string + var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI + var gasPriceErr, gasCostErr error + + l1GasPriceAddress = ArbGasInfoAddress + gasPriceMethod = ArbGasInfo_getL1BaseFeeEstimate + l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(GetL1BaseFeeEstimateAbiString)) + l1GasCostAddress = ArbNodeInterfaceAddress + gasCostMethod = ArbNodeInterface_gasEstimateL1Component + l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GasEstimateL1ComponentAbiString)) + + if gasPriceErr != nil { + panic("Failed to parse L1 gas price method ABI for chain: arbitrum") + } + if gasCostErr != nil { + panic("Failed to parse L1 gas cost method ABI for chain: arbitrum") + } + + return &arbitrumL1Oracle{ + client: ethClient, + pollPeriod: PollPeriod, + logger: logger.Sugared(logger.Named(lggr, "L1GasOracle(arbitrum)")), + chainType: config.ChainArbitrum, + + l1GasPriceAddress: l1GasPriceAddress, + gasPriceMethod: gasPriceMethod, + l1GasPriceMethodAbi: l1GasPriceMethodAbi, + l1GasCostAddress: l1GasCostAddress, + gasCostMethod: gasCostMethod, + l1GasCostMethodAbi: l1GasCostMethodAbi, + + chInitialised: make(chan struct{}), + chStop: make(chan struct{}), + chDone: make(chan struct{}), + } +} + +func (o *arbitrumL1Oracle) Name() string { + return o.logger.Name() +} + +func (o *arbitrumL1Oracle) Start(ctx context.Context) error { + return o.StartOnce(o.Name(), func() error { + go o.run() + <-o.chInitialised + return nil + }) +} +func (o *arbitrumL1Oracle) Close() error { + return o.StopOnce(o.Name(), func() error { + close(o.chStop) + <-o.chDone + return nil + }) +} + +func (o *arbitrumL1Oracle) HealthReport() map[string]error { + return map[string]error{o.Name(): o.Healthy()} +} + +func (o *arbitrumL1Oracle) run() { + defer close(o.chDone) + + t := o.refresh() + close(o.chInitialised) + + for { + select { + case <-o.chStop: + return + case <-t.C: + t = o.refresh() + } + } +} +func (o *arbitrumL1Oracle) refresh() (t *time.Timer) { + t, err := o.refreshWithError() + if err != nil { + o.SvcErrBuffer.Append(err) + } + return +} + +func (o *arbitrumL1Oracle) refreshWithError() (t *time.Timer, err error) { + t = time.NewTimer(utils.WithJitter(o.pollPeriod)) + + ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) + defer cancel() + + price, err := o.fetchL1GasPrice(ctx) + if err != nil { + return t, err + } + + o.l1GasPriceMu.Lock() + defer o.l1GasPriceMu.Unlock() + o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} + return +} + +func (o *arbitrumL1Oracle) fetchL1GasPrice(ctx context.Context) (price *big.Int, err error) { + var callData, b []byte + precompile := common.HexToAddress(o.l1GasPriceAddress) + callData, err = o.l1GasPriceMethodAbi.Pack(o.gasPriceMethod) + if err != nil { + errMsg := "failed to pack calldata for arbitrum L1 gas price method" + o.logger.Errorf(errMsg) + return nil, fmt.Errorf("%s: %w", errMsg, err) + } + b, err = o.client.CallContract(ctx, ethereum.CallMsg{ + To: &precompile, + Data: callData, + }, nil) + if err != nil { + errMsg := "gas oracle contract call failed" + o.logger.Errorf(errMsg) + return nil, fmt.Errorf("%s: %w", errMsg, err) + } + + if len(b) != 32 { // returns uint256; + errMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 32) + o.logger.Criticalf(errMsg) + return nil, fmt.Errorf(errMsg) + } + price = new(big.Int).SetBytes(b) + return price, nil +} + +func (o *arbitrumL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { + var timestamp time.Time + ok := o.IfStarted(func() { + o.l1GasPriceMu.RLock() + l1GasPrice = o.l1GasPrice.price + timestamp = o.l1GasPrice.timestamp + o.l1GasPriceMu.RUnlock() + }) + if !ok { + return l1GasPrice, fmt.Errorf("L1GasOracle is not started; cannot estimate gas") + } + if l1GasPrice == nil { + return l1GasPrice, fmt.Errorf("failed to get l1 gas price; gas price not set") + } + // Validate the price has been updated within the pollPeriod * 2 + // Allowing double the poll period before declaring the price stale to give ample time for the refresh to process + if time.Since(timestamp) > o.pollPeriod*2 { + return l1GasPrice, fmt.Errorf("gas price is stale") + } + return +} + +// Gets the L1 gas cost for the provided transaction at the specified block num +// If block num is not provided, the value on the latest block num is used +func (o *arbitrumL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { + ctx, cancel := context.WithTimeout(ctx, client.QueryTimeout) + defer cancel() + var callData, b []byte + var err error + + if callData, err = o.l1GasCostMethodAbi.Pack(o.gasCostMethod, tx.To(), false, tx.Data()); err != nil { + return nil, fmt.Errorf("failed to pack calldata for %s L1 gas cost estimation method: %w", o.chainType, err) + } + + precompile := common.HexToAddress(o.l1GasCostAddress) + b, err = o.client.CallContract(ctx, ethereum.CallMsg{ + To: &precompile, + Data: callData, + }, blockNum) + if err != nil { + errorMsg := fmt.Sprintf("gas oracle contract call failed: %v", err) + o.logger.Errorf(errorMsg) + return nil, fmt.Errorf(errorMsg) + } + + var l1GasCost *big.Int + + if len(b) != 8+2*32 { // returns (uint64 gasEstimateForL1, uint256 baseFee, uint256 l1BaseFeeEstimate); + errorMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 8+2*32) + o.logger.Critical(errorMsg) + return nil, fmt.Errorf(errorMsg) + } + l1GasCost = new(big.Int).SetBytes(b[:8]) + + return assets.NewWei(l1GasCost), nil +} + +// callGetPricesInArbGas calls ArbGasInfo.getPricesInArbGas() on the precompile contract ArbGasInfoAddress. +// +// @return (per L2 tx, per L1 calldata unit, per storage allocation) +// function getPricesInArbGas() external view returns (uint256, uint256, uint256); +// +// https://github.com/OffchainLabs/nitro/blob/f7645453cfc77bf3e3644ea1ac031eff629df325/contracts/src/precompiles/ArbGasInfo.sol#L69 + +func (o *arbitrumL1Oracle) GetPricesInArbGas() (perL2Tx uint32, perL1CalldataUnit uint32, err error) { + ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) + defer cancel() + precompile := common.HexToAddress(ArbGasInfoAddress) + b, err := o.client.CallContract(ctx, ethereum.CallMsg{ + To: &precompile, + Data: common.Hex2Bytes(ArbGasInfo_getPricesInArbGas), + }, big.NewInt(-1)) + if err != nil { + return 0, 0, err + } + + if len(b) != 3*32 { // returns (uint256, uint256, uint256); + err = fmt.Errorf("return data length (%d) different than expected (%d)", len(b), 3*32) + return + } + bPerL2Tx := new(big.Int).SetBytes(b[:32]) + bPerL1CalldataUnit := new(big.Int).SetBytes(b[32:64]) + // ignore perStorageAllocation + if !bPerL2Tx.IsUint64() || !bPerL1CalldataUnit.IsUint64() { + err = fmt.Errorf("returned integers are not uint64 (%s, %s)", bPerL2Tx.String(), bPerL1CalldataUnit.String()) + return + } + + perL2TxU64 := bPerL2Tx.Uint64() + perL1CalldataUnitU64 := bPerL1CalldataUnit.Uint64() + if perL2TxU64 > math.MaxUint32 || perL1CalldataUnitU64 > math.MaxUint32 { + err = fmt.Errorf("returned integers are not uint32 (%d, %d)", perL2TxU64, perL1CalldataUnitU64) + return + } + perL2Tx = uint32(perL2TxU64) + perL1CalldataUnit = uint32(perL1CalldataUnitU64) + return +} diff --git a/core/chains/evm/gas/rollups/l1_oracle.go b/core/chains/evm/gas/rollups/l1_oracle.go index ae46071cf0d..05ceb720ab2 100644 --- a/core/chains/evm/gas/rollups/l1_oracle.go +++ b/core/chains/evm/gas/rollups/l1_oracle.go @@ -5,36 +5,35 @@ import ( "fmt" "math/big" "slices" - "strings" - "sync" "time" "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" ) -//go:generate mockery --quiet --name ethClient --output ./mocks/ --case=underscore --structname ETHClient -type ethClient interface { - CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) - BatchCallContext(ctx context.Context, b []rpc.BatchElem) error +// L1Oracle provides interface for fetching L1-specific fee components if the chain is an L2. +// For example, on Optimistic Rollups, this oracle can return rollup-specific l1BaseFee +// +//go:generate mockery --quiet --name L1Oracle --output ./mocks/ --case=underscore +type L1Oracle interface { + services.Service + + GasPrice(ctx context.Context) (*assets.Wei, error) + GetGasCost(ctx context.Context, tx *types.Transaction, blockNum *big.Int) (*assets.Wei, error) } -//go:generate mockery --quiet --name daPriceReader --output ./mocks/ --case=underscore --structname DAPriceReader -type daPriceReader interface { - GetDAGasPrice(ctx context.Context) (*big.Int, error) +//go:generate mockery --quiet --name l1OracleClient --output ./mocks/ --case=underscore --structname L1OracleClient +type l1OracleClient interface { + CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) + BatchCallContext(ctx context.Context, b []rpc.BatchElem) error } type priceEntry struct { @@ -42,71 +41,7 @@ type priceEntry struct { timestamp time.Time } -// Reads L2-specific precompiles and caches the l1GasPrice set by the L2. -type l1Oracle struct { - services.StateMachine - client ethClient - pollPeriod time.Duration - logger logger.SugaredLogger - chainType config.ChainType - - l1GasPriceAddress string - gasPriceMethod string - l1GasPriceMethodAbi abi.ABI - l1GasPriceMu sync.RWMutex - l1GasPrice priceEntry - - l1GasCostAddress string - gasCostMethod string - l1GasCostMethodAbi abi.ABI - - priceReader daPriceReader - - chInitialised chan struct{} - chStop services.StopChan - chDone chan struct{} -} - const ( - // ArbGasInfoAddress is the address of the "Precompiled contract that exists in every Arbitrum chain." - // https://github.com/OffchainLabs/nitro/blob/f7645453cfc77bf3e3644ea1ac031eff629df325/contracts/src/precompiles/ArbGasInfo.sol - ArbGasInfoAddress = "0x000000000000000000000000000000000000006C" - // ArbGasInfo_getL1BaseFeeEstimate is the a hex encoded call to: - // `function getL1BaseFeeEstimate() external view returns (uint256);` - ArbGasInfo_getL1BaseFeeEstimate = "getL1BaseFeeEstimate" - // NodeInterfaceAddress is the address of the precompiled contract that is only available through RPC - // https://github.com/OffchainLabs/nitro/blob/e815395d2e91fb17f4634cad72198f6de79c6e61/nodeInterface/NodeInterface.go#L37 - ArbNodeInterfaceAddress = "0x00000000000000000000000000000000000000C8" - // ArbGasInfo_getPricesInArbGas is the a hex encoded call to: - // `function gasEstimateL1Component(address to, bool contractCreation, bytes calldata data) external payable returns (uint64 gasEstimateForL1, uint256 baseFee, uint256 l1BaseFeeEstimate);` - ArbNodeInterface_gasEstimateL1Component = "gasEstimateL1Component" - - // OPGasOracleAddress is the address of the precompiled contract that exists on OP stack chain. - // This is the case for Optimism and Base. - OPGasOracleAddress = "0x420000000000000000000000000000000000000F" - // OPGasOracle_l1BaseFee is a hex encoded call to: - // `function l1BaseFee() external view returns (uint256);` - OPGasOracle_l1BaseFee = "l1BaseFee" - // OPGasOracle_getL1Fee is a hex encoded call to: - // `function getL1Fee(bytes) external view returns (uint256);` - OPGasOracle_getL1Fee = "getL1Fee" - - // ScrollGasOracleAddress is the address of the precompiled contract that exists on Scroll chain. - ScrollGasOracleAddress = "0x5300000000000000000000000000000000000002" - // ScrollGasOracle_l1BaseFee is a hex encoded call to: - // `function l1BaseFee() external view returns (uint256);` - ScrollGasOracle_l1BaseFee = "l1BaseFee" - // ScrollGasOracle_getL1Fee is a hex encoded call to: - // `function getL1Fee(bytes) external view returns (uint256);` - ScrollGasOracle_getL1Fee = "getL1Fee" - - // GasOracleAddress is the address of the precompiled contract that exists on Kroma chain. - // This is the case for Kroma. - KromaGasOracleAddress = "0x4200000000000000000000000000000000000005" - // GasOracle_l1BaseFee is the a hex encoded call to: - // `function l1BaseFee() external view returns (uint256);` - KromaGasOracle_l1BaseFee = "l1BaseFee" - // Interval at which to poll for L1BaseFee. A good starting point is the L1 block time. PollPeriod = 6 * time.Second ) @@ -117,253 +52,18 @@ func IsRollupWithL1Support(chainType config.ChainType) bool { return slices.Contains(supportedChainTypes, chainType) } -func NewL1GasOracle(lggr logger.Logger, ethClient ethClient, chainType config.ChainType) L1Oracle { - var priceReader daPriceReader - switch chainType { - case config.ChainOptimismBedrock: - priceReader = newOPPriceReader(lggr, ethClient, chainType, OPGasOracleAddress) - case config.ChainKroma: - priceReader = newOPPriceReader(lggr, ethClient, chainType, KromaGasOracleAddress) - default: - priceReader = nil +func NewL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType config.ChainType) L1Oracle { + if !IsRollupWithL1Support(chainType) { + return nil } - return newL1GasOracle(lggr, ethClient, chainType, priceReader) -} - -func newL1GasOracle(lggr logger.Logger, ethClient ethClient, chainType config.ChainType, priceReader daPriceReader) L1Oracle { - var l1GasPriceAddress, gasPriceMethod, l1GasCostAddress, gasCostMethod string - var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI - var gasPriceErr, gasCostErr error - + var l1Oracle L1Oracle switch chainType { + case config.ChainOptimismBedrock, config.ChainKroma, config.ChainScroll: + l1Oracle = NewOpStackL1GasOracle(lggr, ethClient, chainType) case config.ChainArbitrum: - l1GasPriceAddress = ArbGasInfoAddress - gasPriceMethod = ArbGasInfo_getL1BaseFeeEstimate - l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(GetL1BaseFeeEstimateAbiString)) - l1GasCostAddress = ArbNodeInterfaceAddress - gasCostMethod = ArbNodeInterface_gasEstimateL1Component - l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GasEstimateL1ComponentAbiString)) - case config.ChainOptimismBedrock: - l1GasPriceAddress = OPGasOracleAddress - gasPriceMethod = OPGasOracle_l1BaseFee - l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - l1GasCostAddress = OPGasOracleAddress - gasCostMethod = OPGasOracle_getL1Fee - l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GetL1FeeAbiString)) - case config.ChainKroma: - l1GasPriceAddress = KromaGasOracleAddress - gasPriceMethod = KromaGasOracle_l1BaseFee - l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - l1GasCostAddress = "" - gasCostMethod = "" - case config.ChainScroll: - l1GasPriceAddress = ScrollGasOracleAddress - gasPriceMethod = ScrollGasOracle_l1BaseFee - l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - l1GasCostAddress = ScrollGasOracleAddress - gasCostMethod = ScrollGasOracle_getL1Fee - l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GetL1FeeAbiString)) + l1Oracle = NewArbitrumL1GasOracle(lggr, ethClient) default: panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) } - - if gasPriceErr != nil { - panic(fmt.Sprintf("Failed to parse L1 gas price method ABI for chain: %s", chainType)) - } - if gasCostErr != nil { - panic(fmt.Sprintf("Failed to parse L1 gas cost method ABI for chain: %s", chainType)) - } - - return &l1Oracle{ - client: ethClient, - pollPeriod: PollPeriod, - logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("L1GasOracle(%s)", chainType))), - chainType: chainType, - - l1GasPriceAddress: l1GasPriceAddress, - gasPriceMethod: gasPriceMethod, - l1GasPriceMethodAbi: l1GasPriceMethodAbi, - l1GasCostAddress: l1GasCostAddress, - gasCostMethod: gasCostMethod, - l1GasCostMethodAbi: l1GasCostMethodAbi, - - priceReader: priceReader, - - chInitialised: make(chan struct{}), - chStop: make(chan struct{}), - chDone: make(chan struct{}), - } -} - -func (o *l1Oracle) Name() string { - return o.logger.Name() -} - -func (o *l1Oracle) Start(ctx context.Context) error { - return o.StartOnce(o.Name(), func() error { - go o.run() - <-o.chInitialised - return nil - }) -} -func (o *l1Oracle) Close() error { - return o.StopOnce(o.Name(), func() error { - close(o.chStop) - <-o.chDone - return nil - }) -} - -func (o *l1Oracle) HealthReport() map[string]error { - return map[string]error{o.Name(): o.Healthy()} -} - -func (o *l1Oracle) run() { - defer close(o.chDone) - - t := o.refresh() - close(o.chInitialised) - - for { - select { - case <-o.chStop: - return - case <-t.C: - t = o.refresh() - } - } -} -func (o *l1Oracle) refresh() (t *time.Timer) { - t, err := o.refreshWithError() - if err != nil { - o.SvcErrBuffer.Append(err) - } - return -} - -func (o *l1Oracle) refreshWithError() (t *time.Timer, err error) { - t = time.NewTimer(utils.WithJitter(o.pollPeriod)) - - ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) - defer cancel() - - price, err := o.fetchL1GasPrice(ctx) - if err != nil { - return t, err - } - - o.l1GasPriceMu.Lock() - defer o.l1GasPriceMu.Unlock() - o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} - return -} - -func (o *l1Oracle) fetchL1GasPrice(ctx context.Context) (price *big.Int, err error) { - // if dedicated priceReader exists, use the reader - if o.priceReader != nil { - return o.priceReader.GetDAGasPrice(ctx) - } - - var callData, b []byte - precompile := common.HexToAddress(o.l1GasPriceAddress) - callData, err = o.l1GasPriceMethodAbi.Pack(o.gasPriceMethod) - if err != nil { - errMsg := fmt.Sprintf("failed to pack calldata for %s L1 gas price method", o.chainType) - o.logger.Errorf(errMsg) - return nil, fmt.Errorf("%s: %w", errMsg, err) - } - b, err = o.client.CallContract(ctx, ethereum.CallMsg{ - To: &precompile, - Data: callData, - }, nil) - if err != nil { - errMsg := "gas oracle contract call failed" - o.logger.Errorf(errMsg) - return nil, fmt.Errorf("%s: %w", errMsg, err) - } - - if len(b) != 32 { // returns uint256; - errMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 32) - o.logger.Criticalf(errMsg) - return nil, fmt.Errorf(errMsg) - } - price = new(big.Int).SetBytes(b) - return price, nil -} - -func (o *l1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { - var timestamp time.Time - ok := o.IfStarted(func() { - o.l1GasPriceMu.RLock() - l1GasPrice = o.l1GasPrice.price - timestamp = o.l1GasPrice.timestamp - o.l1GasPriceMu.RUnlock() - }) - if !ok { - return l1GasPrice, fmt.Errorf("L1GasOracle is not started; cannot estimate gas") - } - if l1GasPrice == nil { - return l1GasPrice, fmt.Errorf("failed to get l1 gas price; gas price not set") - } - // Validate the price has been updated within the pollPeriod * 2 - // Allowing double the poll period before declaring the price stale to give ample time for the refresh to process - if time.Since(timestamp) > o.pollPeriod*2 { - return l1GasPrice, fmt.Errorf("gas price is stale") - } - return -} - -// Gets the L1 gas cost for the provided transaction at the specified block num -// If block num is not provided, the value on the latest block num is used -func (o *l1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { - ctx, cancel := context.WithTimeout(ctx, client.QueryTimeout) - defer cancel() - var callData, b []byte - var err error - if o.chainType == config.ChainOptimismBedrock || o.chainType == config.ChainScroll { - // Append rlp-encoded tx - var encodedtx []byte - if encodedtx, err = tx.MarshalBinary(); err != nil { - return nil, fmt.Errorf("failed to marshal tx for gas cost estimation: %w", err) - } - if callData, err = o.l1GasCostMethodAbi.Pack(o.gasCostMethod, encodedtx); err != nil { - return nil, fmt.Errorf("failed to pack calldata for %s L1 gas cost estimation method: %w", o.chainType, err) - } - } else if o.chainType == config.ChainArbitrum { - if callData, err = o.l1GasCostMethodAbi.Pack(o.gasCostMethod, tx.To(), false, tx.Data()); err != nil { - return nil, fmt.Errorf("failed to pack calldata for %s L1 gas cost estimation method: %w", o.chainType, err) - } - } else { - return nil, fmt.Errorf("L1 gas cost not supported for this chain: %s", o.chainType) - } - - precompile := common.HexToAddress(o.l1GasCostAddress) - b, err = o.client.CallContract(ctx, ethereum.CallMsg{ - To: &precompile, - Data: callData, - }, blockNum) - if err != nil { - errorMsg := fmt.Sprintf("gas oracle contract call failed: %v", err) - o.logger.Errorf(errorMsg) - return nil, fmt.Errorf(errorMsg) - } - - var l1GasCost *big.Int - if o.chainType == config.ChainOptimismBedrock || o.chainType == config.ChainScroll { - if len(b) != 32 { // returns uint256; - errorMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 32) - o.logger.Critical(errorMsg) - return nil, fmt.Errorf(errorMsg) - } - l1GasCost = new(big.Int).SetBytes(b) - } else if o.chainType == config.ChainArbitrum { - if len(b) != 8+2*32 { // returns (uint64 gasEstimateForL1, uint256 baseFee, uint256 l1BaseFeeEstimate); - errorMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 8+2*32) - o.logger.Critical(errorMsg) - return nil, fmt.Errorf(errorMsg) - } - l1GasCost = new(big.Int).SetBytes(b[:8]) - } - - return assets.NewWei(l1GasCost), nil + return l1Oracle } diff --git a/core/chains/evm/gas/rollups/l1_oracle_test.go b/core/chains/evm/gas/rollups/l1_oracle_test.go index 4f3b67e2ecf..6efdda6bcff 100644 --- a/core/chains/evm/gas/rollups/l1_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_oracle_test.go @@ -1,6 +1,7 @@ package rollups import ( + "errors" "math/big" "strings" "testing" @@ -27,9 +28,9 @@ func TestL1Oracle(t *testing.T) { t.Parallel() t.Run("Unsupported ChainType returns nil", func(t *testing.T) { - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) - assert.Panicsf(t, func() { NewL1GasOracle(logger.Test(t), ethClient, config.ChainCelo) }, "Received unspported chaintype %s", config.ChainCelo) + assert.Nil(t, NewL1GasOracle(logger.Test(t), ethClient, config.ChainCelo)) }) } @@ -37,7 +38,7 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Parallel() t.Run("Calling GasPrice on unstarted L1Oracle returns error", func(t *testing.T) { - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) oracle := NewL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) @@ -50,7 +51,7 @@ func TestL1Oracle_GasPrice(t *testing.T) { l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(GetL1BaseFeeEstimateAbiString)) require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -73,10 +74,34 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Run("Calling GasPrice on started Kroma L1Oracle returns Kroma l1GasPrice", func(t *testing.T) { l1BaseFee := big.NewInt(100) - priceReader := mocks.NewDAPriceReader(t) - priceReader.On("GetDAGasPrice", mock.Anything).Return(l1BaseFee, nil) + l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + require.NoError(t, err) + + isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + require.NoError(t, err) + + ethClient := mocks.NewL1OracleClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + var payload []byte + payload, err = isEcotoneAbiString.Pack("isEcotone") + require.NoError(t, err) + require.Equal(t, payload, callMsg.Data) + assert.Nil(t, blockNumber) + }).Return(nil, errors.New("not ecotone")).Once() - oracle := newL1GasOracle(logger.Test(t), nil, config.ChainKroma, priceReader) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + var payload []byte + payload, err = l1GasPriceMethodAbi.Pack("l1BaseFee") + require.NoError(t, err) + require.Equal(t, payload, callMsg.Data) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainKroma, KromaGasOracleAddress) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) @@ -88,10 +113,34 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Run("Calling GasPrice on started OPStack L1Oracle returns OPStack l1GasPrice", func(t *testing.T) { l1BaseFee := big.NewInt(100) - priceReader := mocks.NewDAPriceReader(t) - priceReader.On("GetDAGasPrice", mock.Anything).Return(l1BaseFee, nil) + l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + require.NoError(t, err) + + isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + require.NoError(t, err) + + ethClient := mocks.NewL1OracleClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + var payload []byte + payload, err = isEcotoneAbiString.Pack("isEcotone") + require.NoError(t, err) + require.Equal(t, payload, callMsg.Data) + assert.Nil(t, blockNumber) + }).Return(nil, errors.New("not ecotone")).Once() - oracle := newL1GasOracle(logger.Test(t), nil, config.ChainOptimismBedrock, priceReader) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + var payload []byte + payload, err = l1GasPriceMethodAbi.Pack("l1BaseFee") + require.NoError(t, err) + require.Equal(t, payload, callMsg.Data) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, OPGasOracleAddress) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) @@ -105,7 +154,20 @@ func TestL1Oracle_GasPrice(t *testing.T) { l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + require.NoError(t, err) + + ethClient := mocks.NewL1OracleClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + var payload []byte + payload, err = isEcotoneAbiString.Pack("isEcotone") + require.NoError(t, err) + require.Equal(t, payload, callMsg.Data) + assert.Nil(t, blockNumber) + }).Return(nil, errors.New("not ecotone")).Once() + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -149,7 +211,7 @@ func TestL1Oracle_GetGasCost(t *testing.T) { result = append(result, baseFee...) result = append(result, l1BaseFeeEstimate...) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -171,7 +233,7 @@ func TestL1Oracle_GetGasCost(t *testing.T) { blockNum := big.NewInt(1000) tx := types.NewTx(&types.LegacyTx{}) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) oracle := NewL1GasOracle(logger.Test(t), ethClient, config.ChainKroma) _, err := oracle.GetGasCost(testutils.Context(t), tx, blockNum) @@ -195,7 +257,7 @@ func TestL1Oracle_GetGasCost(t *testing.T) { encodedTx, err := tx.MarshalBinary() require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -230,7 +292,7 @@ func TestL1Oracle_GetGasCost(t *testing.T) { encodedTx, err := tx.MarshalBinary() require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) diff --git a/core/chains/evm/gas/rollups/mocks/da_price_reader.go b/core/chains/evm/gas/rollups/mocks/da_price_reader.go index 7758f53e436..4157eb1494c 100644 --- a/core/chains/evm/gas/rollups/mocks/da_price_reader.go +++ b/core/chains/evm/gas/rollups/mocks/da_price_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index 101090c0594..79d4d64ecdf 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/rollups/mocks/eth_client.go b/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go similarity index 69% rename from core/chains/evm/gas/rollups/mocks/eth_client.go rename to core/chains/evm/gas/rollups/mocks/l1_oracle_client.go index e5a28f715ad..146f2cd6809 100644 --- a/core/chains/evm/gas/rollups/mocks/eth_client.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -13,13 +13,13 @@ import ( rpc "github.com/ethereum/go-ethereum/rpc" ) -// ETHClient is an autogenerated mock type for the ethClient type -type ETHClient struct { +// L1OracleClient is an autogenerated mock type for the l1OracleClient type +type L1OracleClient struct { mock.Mock } // BatchCallContext provides a mock function with given fields: ctx, b -func (_m *ETHClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { +func (_m *L1OracleClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) if len(ret) == 0 { @@ -37,7 +37,7 @@ func (_m *ETHClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) er } // CallContract provides a mock function with given fields: ctx, msg, blockNumber -func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { +func (_m *L1OracleClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) if len(ret) == 0 { @@ -66,13 +66,13 @@ func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blo return r0, r1 } -// NewETHClient creates a new instance of ETHClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewL1OracleClient creates a new instance of L1OracleClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewETHClient(t interface { +func NewL1OracleClient(t interface { mock.TestingT Cleanup(func()) -}) *ETHClient { - mock := ÐClient{} +}) *L1OracleClient { + mock := &L1OracleClient{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/chains/evm/gas/rollups/models.go b/core/chains/evm/gas/rollups/models.go deleted file mode 100644 index 7aa3d4059dd..00000000000 --- a/core/chains/evm/gas/rollups/models.go +++ /dev/null @@ -1,22 +0,0 @@ -package rollups - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" -) - -// L1Oracle provides interface for fetching L1-specific fee components if the chain is an L2. -// For example, on Optimistic Rollups, this oracle can return rollup-specific l1BaseFee -// -//go:generate mockery --quiet --name L1Oracle --output ./mocks/ --case=underscore -type L1Oracle interface { - services.Service - - GasPrice(ctx context.Context) (*assets.Wei, error) - GetGasCost(ctx context.Context, tx *types.Transaction, blockNum *big.Int) (*assets.Wei, error) -} diff --git a/core/chains/evm/gas/rollups/op_l1_oracle.go b/core/chains/evm/gas/rollups/op_l1_oracle.go new file mode 100644 index 00000000000..e180777fb61 --- /dev/null +++ b/core/chains/evm/gas/rollups/op_l1_oracle.go @@ -0,0 +1,431 @@ +package rollups + +import ( + "context" + "fmt" + "math/big" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + + gethtypes "github.com/ethereum/go-ethereum/core/types" + + "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" +) + +// Reads L2-specific precompiles and caches the l1GasPrice set by the L2. +type OptimismL1Oracle struct { + services.StateMachine + client l1OracleClient + pollPeriod time.Duration + logger logger.SugaredLogger + chainType config.ChainType + + l1OracleAddress string + gasPriceMethod string + l1GasPriceMethodAbi abi.ABI + l1GasPriceMu sync.RWMutex + l1GasPrice priceEntry + + gasCostMethod string + l1GasCostMethodAbi abi.ABI + + chInitialised chan struct{} + chStop services.StopChan + chDone chan struct{} + + isEcotoneMethodAbi abi.ABI + + l1BaseFeeCalldata []byte + isEcotoneCalldata []byte + getL1GasUsedCalldata []byte + getL1FeeCalldata []byte + + isEcotone bool + isEcotoneCheckTs int64 +} + +const ( + // OPStackGasOracle_isEcotone fetches if the OP Stack GasPriceOracle contract has upgraded to Ecotone + OPStackGasOracle_isEcotone = "isEcotone" + // OPStackGasOracle_getL1GasUsed fetches the l1 gas used for given tx bytes + OPStackGasOracle_getL1GasUsed = "getL1GasUsed" + // OPStackGasOracle_isEcotonePollingPeriod is the interval to poll if chain has upgraded to Ecotone + // Set to poll every 4 hours + OPStackGasOracle_isEcotonePollingPeriod = 14400 + // OPStackGasOracleAddress is the address of the precompiled contract that exists on OP stack chain. + // OPStackGasOracle_l1BaseFee fetches the l1 base fee set in the OP Stack GasPriceOracle contract + // OPStackGasOracle_l1BaseFee is a hex encoded call to: + // `function l1BaseFee() external view returns (uint256);` + OPStackGasOracle_l1BaseFee = "l1BaseFee" + // OPStackGasOracle_getL1Fee fetches the l1 fee for given tx bytes + // OPStackGasOracle_getL1Fee is a hex encoded call to: + // `function getL1Fee(bytes) external view returns (uint256);` + OPStackGasOracle_getL1Fee = "getL1Fee" + // This is the case for Optimism and Base. + OPGasOracleAddress = "0x420000000000000000000000000000000000000F" + // GasOracleAddress is the address of the precompiled contract that exists on Kroma chain. + // This is the case for Kroma. + KromaGasOracleAddress = "0x4200000000000000000000000000000000000005" + // ScrollGasOracleAddress is the address of the precompiled contract that exists on Scroll chain. + ScrollGasOracleAddress = "0x5300000000000000000000000000000000000002" +) + +func NewOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType config.ChainType) *OptimismL1Oracle { + var precompileAddress string + switch chainType { + case config.ChainOptimismBedrock: + precompileAddress = OPGasOracleAddress + case config.ChainKroma: + precompileAddress = KromaGasOracleAddress + case config.ChainScroll: + precompileAddress = ScrollGasOracleAddress + default: + panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) + } + return newOpStackL1GasOracle(lggr, ethClient, chainType, precompileAddress) +} + +func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType config.ChainType, precompileAddress string) *OptimismL1Oracle { + var l1OracleAddress, gasPriceMethod, gasCostMethod string + var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI + var gasPriceErr, gasCostErr error + + l1OracleAddress = precompileAddress + gasPriceMethod = OPStackGasOracle_l1BaseFee + l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + gasCostMethod = OPStackGasOracle_getL1Fee + l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GetL1FeeAbiString)) + + if gasPriceErr != nil { + panic(fmt.Sprintf("Failed to parse L1 gas price method ABI for chain: %s", chainType)) + } + if gasCostErr != nil { + panic(fmt.Sprintf("Failed to parse L1 gas cost method ABI for chain: %s", chainType)) + } + + // encode calldata for each method; these calldata will remain the same for each call, we can encode them just once + l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + } + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + } + + isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + } + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + } + + getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + } + getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + } + + getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + } + getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + } + + return &OptimismL1Oracle{ + client: ethClient, + pollPeriod: PollPeriod, + logger: logger.Sugared(logger.Named(lggr, "L1GasOracle(optimismBedrock)")), + chainType: chainType, + + l1OracleAddress: l1OracleAddress, + gasPriceMethod: gasPriceMethod, + l1GasPriceMethodAbi: l1GasPriceMethodAbi, + gasCostMethod: gasCostMethod, + l1GasCostMethodAbi: l1GasCostMethodAbi, + + chInitialised: make(chan struct{}), + chStop: make(chan struct{}), + chDone: make(chan struct{}), + + isEcotoneMethodAbi: isEcotoneMethodAbi, + + l1BaseFeeCalldata: l1BaseFeeCalldata, + isEcotoneCalldata: isEcotoneCalldata, + getL1GasUsedCalldata: getL1GasUsedCalldata, + getL1FeeCalldata: getL1FeeCalldata, + + isEcotone: false, + isEcotoneCheckTs: 0, + } +} + +func (o *OptimismL1Oracle) Name() string { + return o.logger.Name() +} + +func (o *OptimismL1Oracle) Start(ctx context.Context) error { + return o.StartOnce(o.Name(), func() error { + go o.run() + <-o.chInitialised + return nil + }) +} +func (o *OptimismL1Oracle) Close() error { + return o.StopOnce(o.Name(), func() error { + close(o.chStop) + <-o.chDone + return nil + }) +} + +func (o *OptimismL1Oracle) HealthReport() map[string]error { + return map[string]error{o.Name(): o.Healthy()} +} + +func (o *OptimismL1Oracle) run() { + defer close(o.chDone) + + t := o.refresh() + close(o.chInitialised) + + for { + select { + case <-o.chStop: + return + case <-t.C: + t = o.refresh() + } + } +} +func (o *OptimismL1Oracle) refresh() (t *time.Timer) { + t, err := o.refreshWithError() + if err != nil { + o.SvcErrBuffer.Append(err) + } + return +} + +func (o *OptimismL1Oracle) refreshWithError() (t *time.Timer, err error) { + t = time.NewTimer(utils.WithJitter(o.pollPeriod)) + + ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) + defer cancel() + + price, err := o.GetDAGasPrice(ctx) + if err != nil { + return t, err + } + + o.l1GasPriceMu.Lock() + defer o.l1GasPriceMu.Unlock() + o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} + return +} + +func (o *OptimismL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { + var timestamp time.Time + ok := o.IfStarted(func() { + o.l1GasPriceMu.RLock() + l1GasPrice = o.l1GasPrice.price + timestamp = o.l1GasPrice.timestamp + o.l1GasPriceMu.RUnlock() + }) + if !ok { + return l1GasPrice, fmt.Errorf("L1GasOracle is not started; cannot estimate gas") + } + if l1GasPrice == nil { + return l1GasPrice, fmt.Errorf("failed to get l1 gas price; gas price not set") + } + // Validate the price has been updated within the pollPeriod * 2 + // Allowing double the poll period before declaring the price stale to give ample time for the refresh to process + if time.Since(timestamp) > o.pollPeriod*2 { + return l1GasPrice, fmt.Errorf("gas price is stale") + } + return +} + +// Gets the L1 gas cost for the provided transaction at the specified block num +// If block num is not provided, the value on the latest block num is used +func (o *OptimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { + ctx, cancel := context.WithTimeout(ctx, client.QueryTimeout) + defer cancel() + var callData, b []byte + var err error + if o.chainType == config.ChainKroma { + return nil, fmt.Errorf("L1 gas cost not supported for this chain: %s", o.chainType) + } + // Append rlp-encoded tx + var encodedtx []byte + if encodedtx, err = tx.MarshalBinary(); err != nil { + return nil, fmt.Errorf("failed to marshal tx for gas cost estimation: %w", err) + } + if callData, err = o.l1GasCostMethodAbi.Pack(o.gasCostMethod, encodedtx); err != nil { + return nil, fmt.Errorf("failed to pack calldata for %s L1 gas cost estimation method: %w", o.chainType, err) + } + + precompile := common.HexToAddress(o.l1OracleAddress) + b, err = o.client.CallContract(ctx, ethereum.CallMsg{ + To: &precompile, + Data: callData, + }, blockNum) + if err != nil { + errorMsg := fmt.Sprintf("gas oracle contract call failed: %v", err) + o.logger.Errorf(errorMsg) + return nil, fmt.Errorf(errorMsg) + } + + var l1GasCost *big.Int + if len(b) != 32 { // returns uint256; + errorMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 32) + o.logger.Critical(errorMsg) + return nil, fmt.Errorf(errorMsg) + } + l1GasCost = new(big.Int).SetBytes(b) + + return assets.NewWei(l1GasCost), nil +} + +func (o *OptimismL1Oracle) GetDAGasPrice(ctx context.Context) (*big.Int, error) { + isEcotone, err := o.checkIsEcotone(ctx) + if err != nil { + return nil, err + } + + o.logger.Infof("Chain isEcotone result: %t", isEcotone) + + if isEcotone { + return o.getEcotoneGasPrice(ctx) + } + + return o.getV1GasPrice(ctx) +} + +func (o *OptimismL1Oracle) checkIsEcotone(ctx context.Context) (bool, error) { + // if chain is already Ecotone, NOOP + if o.isEcotone { + return true, nil + } + // if time since last check has not exceeded polling period, NOOP + if time.Now().Unix()-o.isEcotoneCheckTs < OPStackGasOracle_isEcotonePollingPeriod { + return false, nil + } + o.isEcotoneCheckTs = time.Now().Unix() + + l1OracleAddress := common.HexToAddress(o.l1OracleAddress) + // confirmed with OP team that isEcotone() is the canonical way to check if the chain has upgraded + b, err := o.client.CallContract(ctx, ethereum.CallMsg{ + To: &l1OracleAddress, + Data: o.isEcotoneCalldata, + }, nil) + + // if the chain has not upgraded to Ecotone, the isEcotone call will revert, this would be expected + if err != nil { + o.logger.Infof("isEcotone() call failed, this can happen if chain has not upgraded: %w", err) + return false, nil + } + + res, err := o.isEcotoneMethodAbi.Unpack(OPStackGasOracle_isEcotone, b) + if err != nil { + return false, fmt.Errorf("failed to unpack isEcotone() return data: %w", err) + } + o.isEcotone = res[0].(bool) + return o.isEcotone, nil +} + +func (o *OptimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error) { + l1OracleAddress := common.HexToAddress(o.l1OracleAddress) + b, err := o.client.CallContract(ctx, ethereum.CallMsg{ + To: &l1OracleAddress, + Data: o.l1BaseFeeCalldata, + }, nil) + if err != nil { + return nil, fmt.Errorf("l1BaseFee() call failed: %w", err) + } + + if len(b) != 32 { + return nil, fmt.Errorf("l1BaseFee() return data length (%d) different than expected (%d)", len(b), 32) + } + return new(big.Int).SetBytes(b), nil +} + +func (o *OptimismL1Oracle) getEcotoneGasPrice(ctx context.Context) (*big.Int, error) { + rpcBatchCalls := []rpc.BatchElem{ + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.getL1GasUsedCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.getL1FeeCalldata), + }, + "latest", + }, + Result: new(string), + }, + } + + err := o.client.BatchCallContext(ctx, rpcBatchCalls) + if err != nil { + return nil, fmt.Errorf("getEcotoneGasPrice batch call failed: %w", err) + } + if rpcBatchCalls[0].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1GasUsed, err) + } + if rpcBatchCalls[1].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1Fee, err) + } + + l1GasUsedResult := *(rpcBatchCalls[0].Result.(*string)) + l1FeeResult := *(rpcBatchCalls[1].Result.(*string)) + + l1GasUsedBytes, err := hexutil.Decode(l1GasUsedResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1GasUsed, err) + } + l1FeeBytes, err := hexutil.Decode(l1FeeResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1Fee, err) + } + + l1GasUsed := new(big.Int).SetBytes(l1GasUsedBytes) + l1Fee := new(big.Int).SetBytes(l1FeeBytes) + + // for the same tx byte, l1Fee / l1GasUsed will give the l1 gas price + // note this price is per l1 gas, not l1 data byte + return new(big.Int).Div(l1Fee, l1GasUsed), nil +} diff --git a/core/chains/evm/gas/rollups/op_price_reader_test.go b/core/chains/evm/gas/rollups/op_l1_oracle_test.go similarity index 90% rename from core/chains/evm/gas/rollups/op_price_reader_test.go rename to core/chains/evm/gas/rollups/op_l1_oracle_test.go index dad12a16366..36e8700faff 100644 --- a/core/chains/evm/gas/rollups/op_price_reader_test.go +++ b/core/chains/evm/gas/rollups/op_l1_oracle_test.go @@ -60,7 +60,7 @@ func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) call := ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -87,7 +87,7 @@ func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil).Once() } - oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) gasPrice, err := oracle.GetDAGasPrice(testutils.Context(t)) if tc.returnBadData { @@ -100,13 +100,13 @@ func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { } } -func setupIsEcotone(t *testing.T, oracleAddress string) *mocks.ETHClient { +func setupIsEcotone(t *testing.T, oracleAddress string) *mocks.L1OracleClient { isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) require.NoError(t, err) isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) require.NoError(t, err) - ethClient := mocks.NewETHClient(t) + ethClient := mocks.NewL1OracleClient(t) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) @@ -142,7 +142,7 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { for _, rE := range rpcElements { require.Equal(t, "eth_call", rE.Method) - require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"].(common.Address).String()) + require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"]) require.Equal(t, "latest", rE.Args[1]) } @@ -155,7 +155,7 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { rpcElements[1].Result = &res2 }).Return(nil).Once() - oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) gasPrice, err := oracle.GetDAGasPrice(testutils.Context(t)) require.NoError(t, err) assert.Equal(t, l1BaseFee, gasPrice) @@ -170,7 +170,7 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { rpcElements[1].Result = &badData }).Return(nil).Once() - oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) _, err := oracle.GetDAGasPrice(testutils.Context(t)) assert.Error(t, err) }) @@ -179,7 +179,7 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { ethClient := setupIsEcotone(t, oracleAddress) ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once() - oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) _, err := oracle.GetDAGasPrice(testutils.Context(t)) assert.Error(t, err) }) @@ -193,7 +193,7 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { rpcElements[1].Error = fmt.Errorf("revert") }).Return(nil).Once() - oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) _, err := oracle.GetDAGasPrice(testutils.Context(t)) assert.Error(t, err) }) diff --git a/core/chains/evm/gas/rollups/op_price_reader.go b/core/chains/evm/gas/rollups/op_price_reader.go deleted file mode 100644 index 2d3d668ad8b..00000000000 --- a/core/chains/evm/gas/rollups/op_price_reader.go +++ /dev/null @@ -1,228 +0,0 @@ -package rollups - -import ( - "context" - "fmt" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - - "github.com/smartcontractkit/chainlink/v2/common/config" -) - -const ( - // OPStackGasOracle_l1BaseFee fetches the l1 base fee set in the OP Stack GasPriceOracle contract - OPStackGasOracle_l1BaseFee = "l1BaseFee" - - // OPStackGasOracle_isEcotone fetches if the OP Stack GasPriceOracle contract has upgraded to Ecotone - OPStackGasOracle_isEcotone = "isEcotone" - - // OPStackGasOracle_getL1GasUsed fetches the l1 gas used for given tx bytes - OPStackGasOracle_getL1GasUsed = "getL1GasUsed" - - // OPStackGasOracle_getL1Fee fetches the l1 fee for given tx bytes - OPStackGasOracle_getL1Fee = "getL1Fee" - - // OPStackGasOracle_isEcotonePollingPeriod is the interval to poll if chain has upgraded to Ecotone - // Set to poll every 4 hours - OPStackGasOracle_isEcotonePollingPeriod = 14400 -) - -type opStackGasPriceReader struct { - client ethClient - logger logger.SugaredLogger - - oracleAddress common.Address - isEcotoneMethodAbi abi.ABI - - l1BaseFeeCalldata []byte - isEcotoneCalldata []byte - getL1GasUsedCalldata []byte - getL1FeeCalldata []byte - - isEcotone bool - isEcotoneCheckTs int64 -} - -func newOPPriceReader(lggr logger.Logger, ethClient ethClient, chainType config.ChainType, oracleAddress string) daPriceReader { - // encode calldata for each method; these calldata will remain the same for each call, we can encode them just once - l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) - } - l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) - } - - isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) - } - isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) - } - - getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) - } - getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) - } - - getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) - } - getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) - if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) - } - - return &opStackGasPriceReader{ - client: ethClient, - logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("OPStackGasOracle(%s)", chainType))), - - oracleAddress: common.HexToAddress(oracleAddress), - isEcotoneMethodAbi: isEcotoneMethodAbi, - - l1BaseFeeCalldata: l1BaseFeeCalldata, - isEcotoneCalldata: isEcotoneCalldata, - getL1GasUsedCalldata: getL1GasUsedCalldata, - getL1FeeCalldata: getL1FeeCalldata, - - isEcotone: false, - isEcotoneCheckTs: 0, - } -} - -func (o *opStackGasPriceReader) GetDAGasPrice(ctx context.Context) (*big.Int, error) { - isEcotone, err := o.checkIsEcotone(ctx) - if err != nil { - return nil, err - } - - o.logger.Infof("Chain isEcotone result: %t", isEcotone) - - if isEcotone { - return o.getEcotoneGasPrice(ctx) - } - - return o.getV1GasPrice(ctx) -} - -func (o *opStackGasPriceReader) checkIsEcotone(ctx context.Context) (bool, error) { - // if chain is already Ecotone, NOOP - if o.isEcotone { - return true, nil - } - // if time since last check has not exceeded polling period, NOOP - if time.Now().Unix()-o.isEcotoneCheckTs < OPStackGasOracle_isEcotonePollingPeriod { - return false, nil - } - o.isEcotoneCheckTs = time.Now().Unix() - - // confirmed with OP team that isEcotone() is the canonical way to check if the chain has upgraded - b, err := o.client.CallContract(ctx, ethereum.CallMsg{ - To: &o.oracleAddress, - Data: o.isEcotoneCalldata, - }, nil) - - // if the chain has not upgraded to Ecotone, the isEcotone call will revert, this would be expected - if err != nil { - o.logger.Infof("isEcotone() call failed, this can happen if chain has not upgraded: %w", err) - return false, nil - } - - res, err := o.isEcotoneMethodAbi.Unpack(OPStackGasOracle_isEcotone, b) - if err != nil { - return false, fmt.Errorf("failed to unpack isEcotone() return data: %w", err) - } - o.isEcotone = res[0].(bool) - return o.isEcotone, nil -} - -func (o *opStackGasPriceReader) getV1GasPrice(ctx context.Context) (*big.Int, error) { - b, err := o.client.CallContract(ctx, ethereum.CallMsg{ - To: &o.oracleAddress, - Data: o.l1BaseFeeCalldata, - }, nil) - if err != nil { - return nil, fmt.Errorf("l1BaseFee() call failed: %w", err) - } - - if len(b) != 32 { - return nil, fmt.Errorf("l1BaseFee() return data length (%d) different than expected (%d)", len(b), 32) - } - return new(big.Int).SetBytes(b), nil -} - -func (o *opStackGasPriceReader) getEcotoneGasPrice(ctx context.Context) (*big.Int, error) { - rpcBatchCalls := []rpc.BatchElem{ - { - Method: "eth_call", - Args: []any{ - map[string]interface{}{ - "from": common.Address{}, - "to": o.oracleAddress, - "data": hexutil.Bytes(o.getL1GasUsedCalldata), - }, - "latest", - }, - Result: new(string), - }, - { - Method: "eth_call", - Args: []any{ - map[string]interface{}{ - "from": common.Address{}, - "to": o.oracleAddress, - "data": hexutil.Bytes(o.getL1FeeCalldata), - }, - "latest", - }, - Result: new(string), - }, - } - - err := o.client.BatchCallContext(ctx, rpcBatchCalls) - if err != nil { - return nil, fmt.Errorf("getEcotoneGasPrice batch call failed: %w", err) - } - if rpcBatchCalls[0].Error != nil { - return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1GasUsed, err) - } - if rpcBatchCalls[1].Error != nil { - return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1Fee, err) - } - - l1GasUsedResult := *(rpcBatchCalls[0].Result.(*string)) - l1FeeResult := *(rpcBatchCalls[1].Result.(*string)) - - l1GasUsedBytes, err := hexutil.Decode(l1GasUsedResult) - if err != nil { - return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1GasUsed, err) - } - l1FeeBytes, err := hexutil.Decode(l1FeeResult) - if err != nil { - return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1Fee, err) - } - - l1GasUsed := new(big.Int).SetBytes(l1GasUsedBytes) - l1Fee := new(big.Int).SetBytes(l1FeeBytes) - - // for the same tx byte, l1Fee / l1GasUsed will give the l1 gas price - // note this price is per l1 gas, not l1 data byte - return new(big.Int).Div(l1Fee, l1GasUsed), nil -} diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index edc1b0f92fa..e947e9109d1 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -19,6 +19,7 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -31,8 +32,7 @@ type suggestedPriceConfig interface { BumpMin() *assets.Wei } -//go:generate mockery --quiet --name rpcClient --output ./mocks/ --case=underscore --structname RPCClient -type rpcClient interface { +type suggestedPriceEstimatorClient interface { CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error } @@ -41,7 +41,7 @@ type SuggestedPriceEstimator struct { services.StateMachine cfg suggestedPriceConfig - client rpcClient + client suggestedPriceEstimatorClient pollPeriod time.Duration logger logger.Logger @@ -52,10 +52,12 @@ type SuggestedPriceEstimator struct { chInitialised chan struct{} chStop services.StopChan chDone chan struct{} + + l1Oracle rollups.L1Oracle } // NewSuggestedPriceEstimator returns a new Estimator which uses the suggested gas price. -func NewSuggestedPriceEstimator(lggr logger.Logger, client rpcClient, cfg suggestedPriceConfig) EvmEstimator { +func NewSuggestedPriceEstimator(lggr logger.Logger, client feeEstimatorClient, cfg suggestedPriceConfig, l1Oracle rollups.L1Oracle) EvmEstimator { return &SuggestedPriceEstimator{ client: client, pollPeriod: 10 * time.Second, @@ -65,6 +67,7 @@ func NewSuggestedPriceEstimator(lggr logger.Logger, client rpcClient, cfg sugges chInitialised: make(chan struct{}), chStop: make(chan struct{}), chDone: make(chan struct{}), + l1Oracle: l1Oracle, } } @@ -72,6 +75,10 @@ func (o *SuggestedPriceEstimator) Name() string { return o.logger.Name() } +func (o *SuggestedPriceEstimator) L1Oracle() rollups.L1Oracle { + return o.l1Oracle +} + func (o *SuggestedPriceEstimator) Start(context.Context) error { return o.StartOnce("SuggestedPriceEstimator", func() error { go o.run() diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 0d52d6ab1b9..4f3c4d307d6 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -29,20 +30,24 @@ func TestSuggestedPriceEstimator(t *testing.T) { cfg := &gas.MockGasEstimatorConfig{BumpPercentF: 10, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1} t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) t.Run("calling GetLegacyGas on started estimator returns prices", func(t *testing.T) { - client := mocks.NewRPCClient(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) @@ -51,10 +56,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) @@ -68,10 +75,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("gas price is lower than global max gas price", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(120) }) @@ -84,10 +93,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) @@ -96,22 +107,28 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling GetDynamicFee always returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) _, err := o.GetDynamicFee(testutils.Context(t), maxGasPrice) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) t.Run("calling BumpLegacyGas on unstarted estimator returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) _, _, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), gasLimit, maxGasPrice, nil) assert.EqualError(t, err, "estimator is not started") }) t.Run("calling BumpDynamicFee always returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) fee := gas.DynamicFee{ FeeCap: assets.NewWeiI(42), TipCap: assets.NewWeiI(5), @@ -121,13 +138,15 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator returns new price buffered with bumpPercent", func(t *testing.T) { - client := mocks.NewRPCClient(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(40) }) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(10), gasLimit, maxGasPrice, nil) require.NoError(t, err) @@ -136,14 +155,16 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator returns new price buffered with bumpMin", func(t *testing.T) { - client := mocks.NewRPCClient(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(40) }) - testCfg := &gas.MockGasEstimatorConfig{BumpPercentF: 1, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1} - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, testCfg) + testCfg := &gas.MockGasEstimatorConfig{BumpPercentF: 1, BumpMinF: assets.NewWei(big.NewInt(1)), BumpThresholdF: 1, LimitMultiplierF: 1} + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, testCfg, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(10), gasLimit, maxGasPrice, nil) require.NoError(t, err) @@ -152,13 +173,15 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator returns original price when lower than previous", func(t *testing.T) { - client := mocks.NewRPCClient(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(5) }) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(10), gasLimit, maxGasPrice, nil) require.NoError(t, err) @@ -167,10 +190,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator returns error, suggested gas price is higher than max gas price", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(42) }) @@ -184,10 +209,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator returns max gas price when suggested price under max but the buffer exceeds it", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) + + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(39) }) @@ -200,10 +227,12 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) @@ -212,14 +241,16 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) t.Run("calling BumpLegacyGas on started estimator if refresh call failed returns price from previous update", func(t *testing.T) { - client := mocks.NewRPCClient(t) - o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) + feeEstimatorClient := mocks.NewFeeEstimatorClient(t) + l1Oracle := rollupMocks.NewL1Oracle(t) + + o := gas.NewSuggestedPriceEstimator(logger.Test(t), feeEstimatorClient, cfg, l1Oracle) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(40) }).Once() - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) + feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index e5131aca422..4e7efb5e809 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -25,6 +25,7 @@ import ( ) func Test_HeadListener_HappyPath(t *testing.T) { + t.Parallel() // Logic: // - spawn a listener instance // - mock SubscribeNewHead/Err/Unsubscribe to track these calls @@ -91,6 +92,7 @@ func Test_HeadListener_HappyPath(t *testing.T) { } func Test_HeadListener_NotReceivingHeads(t *testing.T) { + t.Parallel() // Logic: // - same as Test_HeadListener_HappyPath, but // - send one head, make sure ReceivingHeads() is true @@ -149,6 +151,7 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) { } func Test_HeadListener_SubscriptionErr(t *testing.T) { + t.Parallel() tests := []struct { name string err error diff --git a/core/chains/evm/headtracker/mocks/config.go b/core/chains/evm/headtracker/mocks/config.go index 6cc3900ba42..fea7d4629b5 100644 --- a/core/chains/evm/headtracker/mocks/config.go +++ b/core/chains/evm/headtracker/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 8912bafecdf..9d569ade08d 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -31,14 +31,14 @@ var _ ORM = &DbORM{} type DbORM struct { chainID ubig.Big - db sqlutil.DataSource + ds sqlutil.DataSource } // NewORM creates an ORM scoped to chainID. -func NewORM(chainID big.Int, db sqlutil.DataSource) *DbORM { +func NewORM(chainID big.Int, ds sqlutil.DataSource) *DbORM { return &DbORM{ chainID: ubig.Big(chainID), - db: db, + ds: ds, } } @@ -48,19 +48,19 @@ func (orm *DbORM) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) INSERT INTO evm.heads (hash, number, parent_hash, created_at, timestamp, l1_block_number, evm_chain_id, base_fee_per_gas) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (evm_chain_id, hash) DO NOTHING` - _, err := orm.db.ExecContext(ctx, query, head.Hash, head.Number, head.ParentHash, head.CreatedAt, head.Timestamp, head.L1BlockNumber, orm.chainID, head.BaseFeePerGas) + _, err := orm.ds.ExecContext(ctx, query, head.Hash, head.Number, head.ParentHash, head.CreatedAt, head.Timestamp, head.L1BlockNumber, orm.chainID, head.BaseFeePerGas) return pkgerrors.Wrap(err, "IdempotentInsertHead failed to insert head") } func (orm *DbORM) TrimOldHeads(ctx context.Context, minBlockNumber int64) (err error) { query := `DELETE FROM evm.heads WHERE evm_chain_id = $1 AND number < $2` - _, err = orm.db.ExecContext(ctx, query, orm.chainID, minBlockNumber) + _, err = orm.ds.ExecContext(ctx, query, orm.chainID, minBlockNumber) return err } func (orm *DbORM) LatestHead(ctx context.Context) (head *evmtypes.Head, err error) { head = new(evmtypes.Head) - err = orm.db.GetContext(ctx, head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT 1`, orm.chainID) + err = orm.ds.GetContext(ctx, head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT 1`, orm.chainID) if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } @@ -69,14 +69,14 @@ func (orm *DbORM) LatestHead(ctx context.Context) (head *evmtypes.Head, err erro } func (orm *DbORM) LatestHeads(ctx context.Context, minBlockNumer int64) (heads []*evmtypes.Head, err error) { - err = orm.db.SelectContext(ctx, &heads, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND number >= $2 ORDER BY number DESC, created_at DESC, id DESC`, orm.chainID, minBlockNumer) + err = orm.ds.SelectContext(ctx, &heads, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND number >= $2 ORDER BY number DESC, created_at DESC, id DESC`, orm.chainID, minBlockNumer) err = pkgerrors.Wrap(err, "LatestHeads failed") return } func (orm *DbORM) HeadByHash(ctx context.Context, hash common.Hash) (head *evmtypes.Head, err error) { head = new(evmtypes.Head) - err = orm.db.GetContext(ctx, head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND hash = $2`, orm.chainID, hash) + err = orm.ds.GetContext(ctx, head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND hash = $2`, orm.chainID, hash) if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } diff --git a/core/chains/evm/keystore/mocks/eth.go b/core/chains/evm/keystore/mocks/eth.go index 48bd738fdbe..9c11551e2c2 100644 --- a/core/chains/evm/keystore/mocks/eth.go +++ b/core/chains/evm/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index a96474c0f78..148c36148c2 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -9,14 +9,13 @@ import ( "sync/atomic" "time" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" @@ -60,12 +59,10 @@ type ( Register(listener Listener, opts ListenerOpts) (unsubscribe func()) WasAlreadyConsumed(ctx context.Context, lb Broadcast) (bool, error) - MarkConsumed(ctx context.Context, lb Broadcast) error - - // MarkManyConsumed marks all the provided log broadcasts as consumed. - MarkManyConsumed(ctx context.Context, lbs []Broadcast) error + // ds is optional + MarkConsumed(ctx context.Context, ds sqlutil.DataSource, lb Broadcast) error - // NOTE: WasAlreadyConsumed, MarkConsumed and MarkManyConsumed MUST be used within a single goroutine in order for WasAlreadyConsumed to be accurate + // NOTE: WasAlreadyConsumed, and MarkConsumed MUST be used within a single goroutine in order for WasAlreadyConsumed to be accurate } BroadcasterInTest interface { @@ -422,12 +419,15 @@ func (b *broadcaster) eventLoop(chRawLogs <-chan types.Log, chErr <-chan error) debounceResubscribe := time.NewTicker(1 * time.Second) defer debounceResubscribe.Stop() + ctx, cancel := b.chStop.NewCtx() + defer cancel() + b.logger.Debug("Starting the event loop") for { // Replay requests take priority. select { case req := <-b.replayChannel: - b.onReplayRequest(req) + b.onReplayRequest(ctx, req) return true, nil default: } @@ -456,7 +456,7 @@ func (b *broadcaster) eventLoop(chRawLogs <-chan types.Log, chErr <-chan error) needsResubscribe = b.onChangeSubscriberStatus() || needsResubscribe case req := <-b.replayChannel: - b.onReplayRequest(req) + b.onReplayRequest(ctx, req) return true, nil case <-debounceResubscribe.C: @@ -480,7 +480,7 @@ func (b *broadcaster) eventLoop(chRawLogs <-chan types.Log, chErr <-chan error) } // onReplayRequest clears the pool and sets the block backfill number. -func (b *broadcaster) onReplayRequest(replayReq replayRequest) { +func (b *broadcaster) onReplayRequest(ctx context.Context, replayReq replayRequest) { // notify subscribers that we are about to replay. for subscriber := range b.registrations.registeredSubs { if subscriber.opts.ReplayStartedCallback != nil { @@ -495,11 +495,11 @@ func (b *broadcaster) onReplayRequest(replayReq replayRequest) { b.backfillBlockNumber.Int64 = replayReq.fromBlock b.backfillBlockNumber.Valid = true if replayReq.forceBroadcast { - ctx, cancel := b.chStop.CtxCancel(context.WithTimeout(context.Background(), time.Minute)) - ctx = sqlutil.WithoutDefaultTimeout(ctx) - defer cancel() // Use a longer timeout in the event that a very large amount of logs need to be marked - // as consumed. + // as unconsumed. + var cancel func() + ctx, cancel = context.WithTimeout(sqlutil.WithoutDefaultTimeout(ctx), time.Minute) + defer cancel() err := b.orm.MarkBroadcastsUnconsumed(ctx, replayReq.fromBlock) if err != nil { b.logger.Errorw("Error marking broadcasts as unconsumed", @@ -694,25 +694,12 @@ func (b *broadcaster) WasAlreadyConsumed(ctx context.Context, lb Broadcast) (boo } // MarkConsumed marks the log as having been successfully consumed by the subscriber -func (b *broadcaster) MarkConsumed(ctx context.Context, lb Broadcast) error { - return b.orm.MarkBroadcastConsumed(ctx, lb.RawLog().BlockHash, lb.RawLog().BlockNumber, lb.RawLog().Index, lb.JobID()) -} - -// MarkManyConsumed marks the logs as having been successfully consumed by the subscriber -func (b *broadcaster) MarkManyConsumed(ctx context.Context, lbs []Broadcast) (err error) { - var ( - blockHashes = make([]common.Hash, len(lbs)) - blockNumbers = make([]uint64, len(lbs)) - logIndexes = make([]uint, len(lbs)) - jobIDs = make([]int32, len(lbs)) - ) - for i := range lbs { - blockHashes[i] = lbs[i].RawLog().BlockHash - blockNumbers[i] = lbs[i].RawLog().BlockNumber - logIndexes[i] = lbs[i].RawLog().Index - jobIDs[i] = lbs[i].JobID() +func (b *broadcaster) MarkConsumed(ctx context.Context, ds sqlutil.DataSource, lb Broadcast) error { + orm := b.orm + if ds != nil { + orm = orm.WithDataSource(ds) } - return b.orm.MarkBroadcastsConsumed(ctx, blockHashes, blockNumbers, logIndexes, jobIDs) + return orm.MarkBroadcastConsumed(ctx, lb.RawLog().BlockHash, lb.RawLog().BlockNumber, lb.RawLog().Index, lb.JobID()) } // test only @@ -779,10 +766,7 @@ func (n *NullBroadcaster) TrackedAddressesCount() uint32 { func (n *NullBroadcaster) WasAlreadyConsumed(ctx context.Context, lb Broadcast) (bool, error) { return false, pkgerrors.New(n.ErrMsg) } -func (n *NullBroadcaster) MarkConsumed(ctx context.Context, lb Broadcast) error { - return pkgerrors.New(n.ErrMsg) -} -func (n *NullBroadcaster) MarkManyConsumed(ctx context.Context, lbs []Broadcast) error { +func (n *NullBroadcaster) MarkConsumed(ctx context.Context, ds sqlutil.DataSource, lb Broadcast) error { return pkgerrors.New(n.ErrMsg) } diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 18f396fab9d..0d725b8594b 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -94,7 +94,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, db := pgtest.NewSqlxDB(t) orm := log.NewORM(db, cltest.FixtureChainID) lb := log.NewTestBroadcaster(orm, ethClient, config.EVM(), lggr, highestSeenHead, mailMon) - kst := cltest.NewKeyStore(t, db, globalConfig.Database()) + kst := cltest.NewKeyStore(t, db) cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{ Client: ethClient, @@ -110,7 +110,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, m[r.Chain().ID().String()] = r.Chain() } legacyChains := legacyevm.NewLegacyChains(m, cc.AppConfig().EVMConfigs()) - pipelineHelper := cltest.NewJobPipelineV2(t, config.WebServer(), config.JobPipeline(), config.Database(), legacyChains, db, kst, nil, nil) + pipelineHelper := cltest.NewJobPipelineV2(t, globalConfig.WebServer(), globalConfig.JobPipeline(), globalConfig.Database(), legacyChains, db, kst, nil, nil) return &broadcasterHelper{ t: t, @@ -281,7 +281,7 @@ func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { listener.skipMarkingConsumed.Store(skip) } -func (listener *simpleLogListener) HandleLog(lb log.Broadcast) { +func (listener *simpleLogListener) HandleLog(ctx context.Context, lb log.Broadcast) { listener.received.Lock() defer listener.received.Unlock() listener.lggr.Tracef("Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index 4bdb43d9521..fd6b375d80a 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -263,8 +263,6 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { log2 := blocks.LogOnBlockNum(log2Block, contract2.Address()) logs := []types.Log{log1, log2} - contract1.On("ParseLog", log1).Return(flux_aggregator_wrapper.FluxAggregatorNewRound{}, nil) - contract2.On("ParseLog", log2).Return(flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, nil) t.Run("pool two logs from subscription, then shut down", func(t *testing.T) { helper := newBroadcasterHelper(t, 0, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) @@ -295,6 +293,8 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) orm := log.NewORM(helper.db, cltest.FixtureChainID) + contract1.On("ParseLog", log1).Return(flux_aggregator_wrapper.FluxAggregatorNewRound{}, nil) + contract2.On("ParseLog", log2).Return(flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, nil) listener := helper.newLogListenerWithJob("one") listener.SkipMarkingConsumed(true) diff --git a/core/chains/evm/log/mocks/abigen_contract.go b/core/chains/evm/log/mocks/abigen_contract.go index fde8949e4fe..3ab5e350505 100644 --- a/core/chains/evm/log/mocks/abigen_contract.go +++ b/core/chains/evm/log/mocks/abigen_contract.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/mocks/broadcast.go b/core/chains/evm/log/mocks/broadcast.go index 6d9a83716d5..1f1817474ec 100644 --- a/core/chains/evm/log/mocks/broadcast.go +++ b/core/chains/evm/log/mocks/broadcast.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index 26fe1a35101..221456c508b 100644 --- a/core/chains/evm/log/mocks/broadcaster.go +++ b/core/chains/evm/log/mocks/broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -8,6 +8,8 @@ import ( log "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" mock "github.com/stretchr/testify/mock" + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -102,35 +104,17 @@ func (_m *Broadcaster) IsConnected() bool { return r0 } -// MarkConsumed provides a mock function with given fields: ctx, lb -func (_m *Broadcaster) MarkConsumed(ctx context.Context, lb log.Broadcast) error { - ret := _m.Called(ctx, lb) +// MarkConsumed provides a mock function with given fields: ctx, ds, lb +func (_m *Broadcaster) MarkConsumed(ctx context.Context, ds sqlutil.DataSource, lb log.Broadcast) error { + ret := _m.Called(ctx, ds, lb) if len(ret) == 0 { panic("no return value specified for MarkConsumed") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, log.Broadcast) error); ok { - r0 = rf(ctx, lb) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MarkManyConsumed provides a mock function with given fields: ctx, lbs -func (_m *Broadcaster) MarkManyConsumed(ctx context.Context, lbs []log.Broadcast) error { - ret := _m.Called(ctx, lbs) - - if len(ret) == 0 { - panic("no return value specified for MarkManyConsumed") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []log.Broadcast) error); ok { - r0 = rf(ctx, lbs) + if rf, ok := ret.Get(0).(func(context.Context, sqlutil.DataSource, log.Broadcast) error); ok { + r0 = rf(ctx, ds, lb) } else { r0 = ret.Error(0) } diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index 71c9675d6fd..6e94d3bf8a8 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -3,16 +3,13 @@ package log import ( "context" "database/sql" - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/jmoiron/sqlx" pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) @@ -31,8 +28,6 @@ type ORM interface { WasBroadcastConsumed(ctx context.Context, blockHash common.Hash, logIndex uint, jobID int32) (bool, error) // MarkBroadcastConsumed marks the log broadcast as consumed by jobID. MarkBroadcastConsumed(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error - // MarkBroadcastsConsumed marks the log broadcasts as consumed by jobID. - MarkBroadcastsConsumed(ctx context.Context, blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32) error // MarkBroadcastsUnconsumed marks all log broadcasts from all jobs on or after fromBlock as // unconsumed. MarkBroadcastsUnconsumed(ctx context.Context, fromBlock int64) error @@ -45,20 +40,23 @@ type ORM interface { // Reinitialize cleans up the database by removing any unconsumed broadcasts, then updating (if necessary) and // returning the pending minimum block number. Reinitialize(ctx context.Context) (blockNumber *int64, err error) + + WithDataSource(sqlutil.DataSource) ORM } type orm struct { - db sqlutil.DataSource + ds sqlutil.DataSource evmChainID ubig.Big } var _ ORM = (*orm)(nil) -func NewORM(db sqlutil.DataSource, evmChainID big.Int) *orm { - return &orm{ - db: db, - evmChainID: *ubig.New(&evmChainID), - } +func NewORM(ds sqlutil.DataSource, evmChainID big.Int) *orm { + return &orm{ds, *ubig.New(&evmChainID)} +} + +func (o *orm) WithDataSource(ds sqlutil.DataSource) ORM { + return &orm{ds, o.evmChainID} } func (o *orm) WasBroadcastConsumed(ctx context.Context, blockHash common.Hash, logIndex uint, jobID int32) (consumed bool, err error) { @@ -75,7 +73,7 @@ func (o *orm) WasBroadcastConsumed(ctx context.Context, blockHash common.Hash, l jobID, o.evmChainID, } - err = o.db.GetContext(ctx, &consumed, query, args...) + err = o.ds.GetContext(ctx, &consumed, query, args...) if pkgerrors.Is(err, sql.ErrNoRows) { return false, nil } @@ -90,7 +88,7 @@ func (o *orm) FindBroadcasts(ctx context.Context, fromBlockNum int64, toBlockNum AND block_number <= $2 AND evm_chain_id = $3 ` - err := o.db.SelectContext(ctx, &broadcasts, query, fromBlockNum, toBlockNum, o.evmChainID) + err := o.ds.SelectContext(ctx, &broadcasts, query, fromBlockNum, toBlockNum, o.evmChainID) if err != nil { return nil, pkgerrors.Wrap(err, "failed to find log broadcasts") } @@ -98,7 +96,7 @@ func (o *orm) FindBroadcasts(ctx context.Context, fromBlockNum int64, toBlockNum } func (o *orm) CreateBroadcast(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error { - _, err := o.db.ExecContext(ctx, ` + _, err := o.ds.ExecContext(ctx, ` INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) VALUES ($1, $2, $3, $4, NOW(), NOW(), false, $5) `, blockHash, blockNumber, logIndex, jobID, o.evmChainID) @@ -106,7 +104,7 @@ func (o *orm) CreateBroadcast(ctx context.Context, blockHash common.Hash, blockN } func (o *orm) MarkBroadcastConsumed(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error { - _, err := o.db.ExecContext(ctx, ` + _, err := o.ds.ExecContext(ctx, ` INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) VALUES ($1, $2, $3, $4, NOW(), NOW(), true, $5) ON CONFLICT (job_id, block_hash, log_index, evm_chain_id) DO UPDATE @@ -115,45 +113,9 @@ func (o *orm) MarkBroadcastConsumed(ctx context.Context, blockHash common.Hash, return pkgerrors.Wrap(err, "failed to mark log broadcast as consumed") } -// MarkBroadcastsConsumed marks many broadcasts as consumed. -// The lengths of all the provided slices must be equal, otherwise an error is returned. -func (o *orm) MarkBroadcastsConsumed(ctx context.Context, blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32) error { - if !utils.AllEqual(len(blockHashes), len(blockNumbers), len(logIndexes), len(jobIDs)) { - return fmt.Errorf("all arg slice lengths must be equal, got: %d %d %d %d", - len(blockHashes), len(blockNumbers), len(logIndexes), len(jobIDs), - ) - } - - type input struct { - BlockHash common.Hash `db:"blockHash"` - BlockNumber uint64 `db:"blockNumber"` - LogIndex uint `db:"logIndex"` - JobID int32 `db:"jobID"` - ChainID ubig.Big `db:"chainID"` - } - inputs := make([]input, len(blockHashes)) - query := ` -INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) -VALUES (:blockHash, :blockNumber, :logIndex, :jobID, NOW(), NOW(), true, :chainID) -ON CONFLICT (job_id, block_hash, log_index, evm_chain_id) DO UPDATE -SET consumed = true, updated_at = NOW(); - ` - for i := range blockHashes { - inputs[i] = input{ - BlockHash: blockHashes[i], - BlockNumber: blockNumbers[i], - LogIndex: logIndexes[i], - JobID: jobIDs[i], - ChainID: o.evmChainID, - } - } - _, err := o.db.(*sqlx.DB).NamedExecContext(ctx, query, inputs) - return pkgerrors.Wrap(err, "mark broadcasts consumed") -} - // MarkBroadcastsUnconsumed implements the ORM interface. func (o *orm) MarkBroadcastsUnconsumed(ctx context.Context, fromBlock int64) error { - _, err := o.db.ExecContext(ctx, ` + _, err := o.ds.ExecContext(ctx, ` UPDATE log_broadcasts SET consumed = false WHERE block_number >= $1 @@ -193,7 +155,7 @@ func (o *orm) Reinitialize(ctx context.Context) (*int64, error) { } func (o *orm) SetPendingMinBlock(ctx context.Context, blockNumber *int64) error { - _, err := o.db.ExecContext(ctx, ` + _, err := o.ds.ExecContext(ctx, ` INSERT INTO log_broadcasts_pending (evm_chain_id, block_number, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (evm_chain_id) DO UPDATE SET block_number = $3, updated_at = NOW() `, o.evmChainID, blockNumber, blockNumber) @@ -202,7 +164,7 @@ func (o *orm) SetPendingMinBlock(ctx context.Context, blockNumber *int64) error func (o *orm) GetPendingMinBlock(ctx context.Context) (*int64, error) { var blockNumber *int64 - err := o.db.GetContext(ctx, &blockNumber, ` + err := o.ds.GetContext(ctx, &blockNumber, ` SELECT block_number FROM log_broadcasts_pending WHERE evm_chain_id = $1 `, o.evmChainID) if pkgerrors.Is(err, sql.ErrNoRows) { @@ -215,7 +177,7 @@ func (o *orm) GetPendingMinBlock(ctx context.Context) (*int64, error) { func (o *orm) getUnconsumedMinBlock(ctx context.Context) (*int64, error) { var blockNumber *int64 - err := o.db.GetContext(ctx, &blockNumber, ` + err := o.ds.GetContext(ctx, &blockNumber, ` SELECT min(block_number) FROM log_broadcasts WHERE evm_chain_id = $1 AND consumed = false @@ -230,7 +192,7 @@ func (o *orm) getUnconsumedMinBlock(ctx context.Context) (*int64, error) { } func (o *orm) removeUnconsumed(ctx context.Context) error { - _, err := o.db.ExecContext(ctx, ` + _, err := o.ds.ExecContext(ctx, ` DELETE FROM log_broadcasts WHERE evm_chain_id = $1 AND consumed = false diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index ba9509d4518..dc3611e8e6f 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -13,15 +13,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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" ) func TestORM_broadcasts(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - ctx := testutils.Context(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() orm := log.NewORM(db, cltest.FixtureChainID) @@ -44,12 +41,12 @@ func TestORM_broadcasts(t *testing.T) { require.Zero(t, rowsAffected) t.Run("WasBroadcastConsumed_DNE", func(t *testing.T) { - _, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) + _, err := orm.WasBroadcastConsumed(testutils.Context(t), rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) }) require.True(t, t.Run("CreateBroadcast", func(t *testing.T) { - err := orm.CreateBroadcast(ctx, rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) + err := orm.CreateBroadcast(testutils.Context(t), rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) require.NoError(t, err) var consumed null.Bool @@ -59,13 +56,13 @@ func TestORM_broadcasts(t *testing.T) { })) t.Run("WasBroadcastConsumed_false", func(t *testing.T) { - was, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) + was, err := orm.WasBroadcastConsumed(testutils.Context(t), rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) require.False(t, was) }) require.True(t, t.Run("MarkBroadcastConsumed", func(t *testing.T) { - err := orm.MarkBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) + err := orm.MarkBroadcastConsumed(testutils.Context(t), rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) require.NoError(t, err) var consumed null.Bool @@ -74,66 +71,17 @@ func TestORM_broadcasts(t *testing.T) { require.Equal(t, null.BoolFrom(true), consumed) })) - t.Run("MarkBroadcastsConsumed Success", func(t *testing.T) { - var ( - err error - blockHashes []common.Hash - blockNumbers []uint64 - logIndexes []uint - jobIDs []int32 - ) - for i := 0; i < 3; i++ { - l := cltest.RandomLog(t) - err = orm.CreateBroadcast(ctx, l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) - require.NoError(t, err) - blockHashes = append(blockHashes, l.BlockHash) - blockNumbers = append(blockNumbers, l.BlockNumber) - logIndexes = append(logIndexes, l.Index) - jobIDs = append(jobIDs, listener.JobID()) - - } - err = orm.MarkBroadcastsConsumed(ctx, blockHashes, blockNumbers, logIndexes, jobIDs) - require.NoError(t, err) - - for i := range blockHashes { - was, err := orm.WasBroadcastConsumed(ctx, blockHashes[i], logIndexes[i], jobIDs[i]) - require.NoError(t, err) - require.True(t, was) - } - }) - - t.Run("MarkBroadcastsConsumed Failure", func(t *testing.T) { - var ( - err error - blockHashes []common.Hash - blockNumbers []uint64 - logIndexes []uint - jobIDs []int32 - ) - for i := 0; i < 5; i++ { - l := cltest.RandomLog(t) - err = orm.CreateBroadcast(ctx, l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) - require.NoError(t, err) - blockHashes = append(blockHashes, l.BlockHash) - blockNumbers = append(blockNumbers, l.BlockNumber) - logIndexes = append(logIndexes, l.Index) - jobIDs = append(jobIDs, listener.JobID()) - } - err = orm.MarkBroadcastsConsumed(ctx, blockHashes[:len(blockHashes)-2], blockNumbers, logIndexes, jobIDs) - require.Error(t, err) - }) - t.Run("WasBroadcastConsumed_true", func(t *testing.T) { - was, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) + was, err := orm.WasBroadcastConsumed(testutils.Context(t), rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) require.True(t, was) }) } func TestORM_pending(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) orm := log.NewORM(db, cltest.FixtureChainID) - ctx := testutils.Context(t) num, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) @@ -156,10 +104,9 @@ func TestORM_pending(t *testing.T) { } func TestORM_MarkUnconsumed(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) ctx := testutils.Context(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + db := pgtest.NewSqlxDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() orm := log.NewORM(db, cltest.FixtureChainID) @@ -256,8 +203,8 @@ func TestORM_Reinitialize(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) - orm := log.NewORM(db, cltest.FixtureChainID) ctx := testutils.Context(t) + orm := log.NewORM(db, cltest.FixtureChainID) jobID := cltest.MustInsertV2JobSpec(t, db, common.BigToAddress(big.NewInt(rand.Int63()))).ID diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index b56d3f4aaaa..c82fee43b6e 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -62,7 +62,7 @@ type ( // The Listener responds to log events through HandleLog. Listener interface { - HandleLog(b Broadcast) + HandleLog(ctx context.Context, b Broadcast) JobID() int32 } @@ -240,6 +240,9 @@ func (r *registrations) sendLogs(ctx context.Context, logsToSend []logsOnBlock, for _, log := range logsPerBlock.Logs { handlers.sendLog(ctx, log, latestHead, broadcastsExisting, bc, r.logger) + if ctx.Err() != nil { + return + } } } } @@ -442,7 +445,7 @@ func (r *handler) sendLog(ctx context.Context, log types.Log, latestHead evmtype wg.Add(1) go func() { defer wg.Done() - handleLog(&broadcast{ + handleLog(ctx, &broadcast{ latestBlockNumber, latestHead.Hash, latestHead.ReceiptsRoot, diff --git a/core/chains/evm/log/registrations_test.go b/core/chains/evm/log/registrations_test.go index 2be01dca2bf..8c0beaa9379 100644 --- a/core/chains/evm/log/registrations_test.go +++ b/core/chains/evm/log/registrations_test.go @@ -1,6 +1,7 @@ package log import ( + "context" "testing" "github.com/ethereum/go-ethereum/common" @@ -18,8 +19,8 @@ type testListener struct { jobID int32 } -func (tl testListener) JobID() int32 { return tl.jobID } -func (tl testListener) HandleLog(Broadcast) { panic("not implemented") } +func (tl testListener) JobID() int32 { return tl.jobID } +func (tl testListener) HandleLog(context.Context, Broadcast) { panic("not implemented") } func newTestListener(t *testing.T, jobID int32) testListener { return testListener{jobID} diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index a8eabaff115..548e9ca3b90 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index f03fd8829cc..7c55cd78ebd 100644 --- a/core/chains/evm/mocks/balance_monitor.go +++ b/core/chains/evm/mocks/balance_monitor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/mocks/node.go b/core/chains/evm/mocks/node.go index 25944cfcf42..6a939d5e844 100644 --- a/core/chains/evm/mocks/node.go +++ b/core/chains/evm/mocks/node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/mocks/send_only_node.go b/core/chains/evm/mocks/send_only_node.go index 8ec3270281d..e0ab9775be9 100644 --- a/core/chains/evm/mocks/send_only_node.go +++ b/core/chains/evm/mocks/send_only_node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index 85e0ec669bf..a27e2cec9a7 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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" ) @@ -35,11 +34,9 @@ func newEthClientMock(t *testing.T) *evmclimocks.Client { func TestBalanceMonitor_Start(t *testing.T) { t.Parallel() - cfg := configtest.NewGeneralConfig(t, nil) - t.Run("updates balance from nil for multiple keys", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := newEthClientMock(t) _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -66,7 +63,7 @@ func TestBalanceMonitor_Start(t *testing.T) { t.Run("handles nil head", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := newEthClientMock(t) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -85,7 +82,7 @@ func TestBalanceMonitor_Start(t *testing.T) { t.Run("cancelled context", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := newEthClientMock(t) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -114,7 +111,7 @@ func TestBalanceMonitor_Start(t *testing.T) { t.Run("recovers on error", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := newEthClientMock(t) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -136,11 +133,9 @@ func TestBalanceMonitor_Start(t *testing.T) { func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { t.Parallel() - cfg := configtest.NewGeneralConfig(t, nil) - t.Run("updates balance for multiple keys", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := newEthClientMock(t) _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -190,8 +185,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 02af83073e8..4e19a2ec7da 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -54,6 +54,7 @@ func NewTestEthBroadcaster( txStore txmgr.TestEvmTxStore, ethClient client.Client, keyStore keystore.Eth, + gconfig chainlink.GeneralConfig, config evmconfig.ChainScopedConfig, checkerFactory txmgr.TransmitCheckerFactory, nonceAutoSync bool, @@ -64,11 +65,11 @@ func NewTestEthBroadcaster( lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { - return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr) - }, ge.EIP1559DynamicFees(), nil, ge) + estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), nil, ge.BlockHistory(), lggr, nil) + }, ge.EIP1559DynamicFees(), ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) - ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync) + ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), gconfig.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync) // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() @@ -81,7 +82,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -93,7 +94,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), - evmcfg.Database().Listener(), + cfg.Database().Listener(), ethKeyStore, txBuilder, logger.Test(t), @@ -139,7 +140,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -151,7 +152,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), - evmcfg.Database().Listener(), + cfg.Database().Listener(), ethKeyStore, txBuilder, logger.Test(t), @@ -170,7 +171,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ctx := testutils.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -182,8 +183,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) - + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") timeNow := time.Now() @@ -383,7 +383,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { evmcfg = evmtest.NewChainScopedConfig(t, cfg) ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(1), nil).Once() nonceTracker = txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) + eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -525,7 +525,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ctx := testutils.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -533,7 +533,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { checkerFactory := &testCheckerFactory{} ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -611,7 +611,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -674,7 +674,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -682,7 +682,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) @@ -723,7 +723,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) firstInProgress := txmgr.Tx{ @@ -758,13 +758,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm.key_states.next_nonce has not been @@ -797,13 +797,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -834,13 +834,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -870,13 +870,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -908,13 +908,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -944,7 +944,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := pgtest.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -956,7 +956,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -1013,7 +1013,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -1022,7 +1022,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { lggr := logger.Test(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmClient) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := testutils.Context(t) require.NoError(t, commonutils.JustError(db.Exec(`SET CONSTRAINTS fk_pipeline_runs_pruning_key DEFERRED`))) @@ -1113,7 +1113,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("with erroring callback bails out", func(t *testing.T) { require.NoError(t, txStore.InsertTx(ctx, &etx)) - fn := func(id uuid.UUID, result interface{}, err error) error { + fn := func(ctx context.Context, id uuid.UUID, result interface{}, err error) error { return errors.New("something exploded in the callback") } @@ -1130,7 +1130,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }) t.Run("calls resume with error", func(t *testing.T) { - fn := func(id uuid.UUID, result interface{}, err error) error { + fn := func(ctx context.Context, id uuid.UUID, result interface{}, err error) error { require.Equal(t, id, tr.ID) require.Nil(t, result) require.Error(t, err) @@ -1152,12 +1152,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { - estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { - return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) - }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil, evmcfg.EVM().GasEstimator()) + estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator()) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) - eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false) + eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1481,7 +1481,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1573,7 +1573,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { })) localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) @@ -1604,7 +1604,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) })) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) @@ -1619,7 +1619,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { })) localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1655,7 +1655,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - realKeystore := cltest.NewKeyStore(t, db, cfg.Database()) + realKeystore := cltest.NewKeyStore(t, db) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, realKeystore.Eth()) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -1667,7 +1667,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := testutils.Context(t) _, err := nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) @@ -1712,11 +1712,11 @@ func TestEthBroadcaster_Trigger(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) eb.Trigger(testutils.NewAddress()) eb.Trigger(testutils.NewAddress()) @@ -1735,12 +1735,12 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { evmTxmCfg := txmgr.NewEvmTxmConfig(evmcfg.EVM()) txStore := cltest.NewTestTxStore(t, db) - kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + kst := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst) - estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { - return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) - }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil, evmcfg.EVM().GasEstimator()) + estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator()) checkerFactory := &testCheckerFactory{} ge := evmcfg.EVM().GasEstimator() @@ -1770,7 +1770,7 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -1788,7 +1788,7 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { // Tx with nonce 0 in DB will set local nonce map to value to 1 mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(inProgressTxNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) // Check the local nonce map was set to 1 higher than in-progress tx nonce nonce := getLocalNextNonce(t, nonceTracker, fromAddress) diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index fbe21b54d81..44449b7a44f 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -1,6 +1,7 @@ package txmgr_test import ( + "context" "encoding/json" "errors" "fmt" @@ -45,9 +46,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) -func newTestChainScopedConfig(t *testing.T) evmconfig.ChainScopedConfig { +func newTestChainScopedConfig(t *testing.T) (chainlink.GeneralConfig, evmconfig.ChainScopedConfig) { cfg := configtest.NewTestGeneralConfig(t) - return evmtest.NewChainScopedConfig(t, cfg) + return cfg, evmtest.NewChainScopedConfig(t, cfg) } func newBroadcastLegacyEthTxAttempt(t *testing.T, etxID int64, gasPrice ...int64) txmgr.TxAttempt { @@ -113,11 +114,11 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - config := newTestChainScopedConfig(t) + gconfig, config := newTestChainScopedConfig(t) txStore := newTxStore(t, db) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() // Add some fromAddresses cltest.MustInsertRandomKey(t, ethKeyStore) @@ -126,9 +127,9 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { newEst := func(logger.Logger) gas.EvmEstimator { return estimator } lggr := logger.Test(t) ge := config.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) + feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ethKeyStore, txBuilder, lggr) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ethKeyStore, txBuilder, lggr) ctx := testutils.Context(t) // Can't close unstarted instance @@ -183,15 +184,15 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - config := newTestChainScopedConfig(t) + gconfig, config := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) nonce := int64(0) ctx := testutils.Context(t) @@ -600,7 +601,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -608,7 +609,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -663,12 +664,12 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // tx is not forwarded and doesn't have meta set. EthConfirmer should handle nil meta values etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -713,7 +714,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -721,7 +722,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) var attempts []txmgr.TxAttempt @@ -766,16 +767,16 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t t.Parallel() db := pgtest.NewSqlxDB(t) - config := newTestChainScopedConfig(t) + gconfig, config := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -796,7 +797,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress1_2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -806,7 +807,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(20), nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -865,7 +866,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -873,7 +874,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1125,7 +1126,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1133,7 +1134,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1204,7 +1205,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1212,7 +1213,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1268,7 +1269,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1276,7 +1277,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1340,7 +1341,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmFromAddress := fromAddress @@ -1359,7 +1360,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { lggr := logger.Test(t) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) t.Run("returns nothing when there are no transactions", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1638,7 +1639,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing ctx := testutils.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) kst := ksmocks.NewEth(t) @@ -1646,7 +1647,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing newEst := func(logger.Logger) gas.EvmEstimator { return estimator } estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint64(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) + feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -1685,7 +1686,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing ctx := testutils.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) kst := ksmocks.NewEth(t) @@ -1694,7 +1695,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing newEst := func(logger.Logger) gas.EvmEstimator { return estimator } // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) + feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -1734,7 +1735,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -1745,7 +1746,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -1802,7 +1803,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -1813,7 +1814,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -2246,7 +2247,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60500000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, gcfg, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2276,7 +2277,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60480000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, gcfg, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2344,7 +2345,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(1000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2 := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + ec2 := newEthConfirmer(t, txStore, ethClient, gcfg, newCfg, ethKeyStore, nil) // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { @@ -2413,7 +2414,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -2430,7 +2431,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("terminally underpriced transaction with in_progress attempt is retried with more gas", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) originalBroadcastAt := time.Unix(1616509100, 0) etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) @@ -2454,7 +2455,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in legacy mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2486,7 +2487,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in EIP-1559 mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2520,12 +2521,11 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -2535,7 +2535,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // keyStates, err := ethKeyStore.GetStatesForKeys(keys) // require.NoError(t, err) - config := newTestChainScopedConfig(t) + gconfig, config := newTestChainScopedConfig(t) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -2551,7 +2551,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { insufficientEthError := errors.New("insufficient funds for gas * price + value") t.Run("saves attempt with state 'insufficient_eth' if eth node returns this error", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2577,7 +2577,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("does not bump gas when previous error was 'out of eth', instead resubmits existing transaction", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2602,7 +2602,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("saves the attempt as broadcast after node wallet has been topped up with sufficient balance", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2634,7 +2634,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { c.EVM[0].GasEstimator.BumpTxDepth = ptr(uint32(depth)) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) for i := 0; i < etxCount; i++ { n := nonce @@ -2659,18 +2659,17 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ctx := testutils.Context(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - config := newTestChainScopedConfig(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + gconfig, config := newTestChainScopedConfig(t) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -2834,13 +2833,12 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - config := newTestChainScopedConfig(t) + gconfig, config := newTestChainScopedConfig(t) mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) mustInsertInProgressEthTx(t, txStore, 0, fromAddress) etx1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) @@ -2851,7 +2849,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts one eth_tx if it falls within in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2866,7 +2864,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2881,7 +2879,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == overrideGasLimit @@ -2895,7 +2893,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) @@ -2921,7 +2919,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == config.EVM().GasEstimator().LimitDefault() @@ -2938,7 +2936,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { config := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -2966,7 +2964,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) t.Run("doesn't process task runs that are not suspended (possibly already previously resumed)", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, config, evmcfg, ethKeyStore, func(context.Context, uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) @@ -2985,7 +2983,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { }) t.Run("doesn't process task runs where the receipt is younger than minConfirmations", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, config, evmcfg, ethKeyStore, func(context.Context, uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) @@ -3006,7 +3004,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { ch := make(chan interface{}) nonce := evmtypes.Nonce(3) var err error - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := newEthConfirmer(t, txStore, ethClient, config, evmcfg, ethKeyStore, func(ctx context.Context, id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil @@ -3059,7 +3057,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { } ch := make(chan data) nonce := evmtypes.Nonce(4) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, err error) error { + ec := newEthConfirmer(t, txStore, ethClient, config, evmcfg, ethKeyStore, func(ctx context.Context, id uuid.UUID, value interface{}, err error) error { ch <- data{value, err} return nil }) @@ -3106,7 +3104,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("does not mark callback complete if callback fails", func(t *testing.T) { nonce := evmtypes.Nonce(5) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := newEthConfirmer(t, txStore, ethClient, config, evmcfg, ethKeyStore, func(context.Context, uuid.UUID, interface{}, error) error { return errors.New("error") }) @@ -3129,14 +3127,14 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { func ptr[T any](t T) *T { return &t } -func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { +func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, gconfig chainlink.GeneralConfig, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { - return gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr) - }, ge.EIP1559DynamicFees(), nil, ge) + estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(ge, nil, ge.BlockHistory(), lggr, nil) + }, ge.EIP1559DynamicFees(), ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) servicetest.Run(t, ec) return ec diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 55f650e934b..c8e664e8cfe 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -1292,26 +1292,28 @@ func (o *evmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *TxAttem return nil } -func (o *evmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.Int) (txes []*Tx, err error) { +func (o *evmTxStore) GetAbandonedTransactionsByBatch(ctx context.Context, chainID *big.Int, enabledAddrs []common.Address, offset, limit uint) (txes []*Tx, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - err = o.Transaction(ctx, true, func(orm *evmTxStore) error { - stmt := `SELECT * FROM evm.txes WHERE state <> 'fatal_error' AND evm_chain_id = $1` - var dbEtxs []DbEthTx - if err = orm.q.SelectContext(ctx, &dbEtxs, stmt, chainID.String()); err != nil { - return fmt.Errorf("failed to load evm.txes: %w", err) - } - txes = make([]*Tx, len(dbEtxs)) - dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) - err = o.LoadTxesAttempts(ctx, txes) - if err != nil { - return fmt.Errorf("failed to load evm.txes: %w", err) - } - return nil - }) - return txes, nil + var enabledAddrsBytea [][]byte + for _, addr := range enabledAddrs { + enabledAddrsBytea = append(enabledAddrsBytea, addr[:]) + } + + // TODO: include confirmed txes https://smartcontract-it.atlassian.net/browse/BCI-2920 + query := `SELECT * FROM evm.txes WHERE state <> 'fatal_error' AND state <> 'confirmed' AND evm_chain_id = $1 + AND from_address <> ALL($2) ORDER BY nonce ASC OFFSET $3 LIMIT $4` + + var dbEtxs []DbEthTx + if err = o.q.SelectContext(ctx, &dbEtxs, query, chainID.String(), enabledAddrsBytea, offset, limit); err != nil { + return nil, fmt.Errorf("failed to load evm.txes: %w", err) + } + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + + return txes, err } func (o *evmTxStore) GetTxByID(ctx context.Context, id int64) (txe *Tx, err error) { @@ -1939,7 +1941,7 @@ func (o *evmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, } // Find transactions loaded with transaction attempts and receipts by transaction IDs and states -func (o *evmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []txmgrtypes.TxState, chainID *big.Int) (txes []*Tx, err error) { +func (o *evmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []txmgrtypes.TxState, chainID *big.Int) (txes []*Tx, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 5bb131862ed..cf38b2d1275 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -7,6 +7,12 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" @@ -25,18 +31,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" ) func TestORM_TransactionsWithAttempts(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -80,9 +80,8 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { func TestORM_Transactions(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -120,8 +119,7 @@ func TestORM(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) orm := cltest.NewTestTxStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) ctx := testutils.Context(t) @@ -188,9 +186,8 @@ func TestORM(t *testing.T) { func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) orm := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -239,11 +236,10 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logCfg := pgtest.NewQConfig(true) txStore := cltest.NewTestTxStore(t, db) ctx := testutils.Context(t) - ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -327,8 +323,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) orm := cltest.NewTestTxStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -376,9 +371,9 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) + _, cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) @@ -445,9 +440,8 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -469,9 +463,8 @@ func TestORM_UpdateTxsUnconfirmed(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) @@ -489,9 +482,8 @@ func TestORM_FindTxAttemptsRequiringReceiptFetch(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -510,9 +502,8 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ctx := testutils.Context(t) @@ -545,9 +536,8 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ctx := testutils.Context(t) @@ -576,9 +566,8 @@ func TestORM_PreloadTxes(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("loads eth transaction", func(t *testing.T) { @@ -610,9 +599,8 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -631,9 +619,8 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -705,9 +692,9 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { func Test_FindTxWithIdempotencyKey(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) + _, cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { @@ -735,9 +722,8 @@ func TestORM_FindTxWithSequence(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { @@ -760,9 +746,8 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ctx := testutils.Context(t) @@ -825,9 +810,8 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -861,9 +845,8 @@ func TestORM_FindEarliestUnconfirmedBroadcastTime(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -885,9 +868,8 @@ func TestORM_FindEarliestUnconfirmedTxAttemptBlock(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -917,9 +899,8 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -942,9 +923,8 @@ func TestORM_SaveSentAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -968,9 +948,8 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -994,9 +973,8 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("deletes in_progress attempt", func(t *testing.T) { @@ -1017,9 +995,8 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("saves new in_progress attempt if attempt is new", func(t *testing.T) { @@ -1059,9 +1036,8 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1099,11 +1075,10 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) ctx := testutils.Context(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1161,10 +1136,9 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) ctx := testutils.Context(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1198,9 +1172,8 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("load eth tx attempt", func(t *testing.T) { @@ -1252,9 +1225,8 @@ func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("replace eth tx attempt", func(t *testing.T) { @@ -1276,9 +1248,8 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1304,9 +1275,8 @@ func TestORM_UpdateTxFatalError(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1329,9 +1299,8 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { @@ -1361,9 +1330,8 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) nonce := evmtypes.Nonce(123) @@ -1395,9 +1363,8 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { }) db = pgtest.NewSqlxDB(t) - cfg = newTestChainScopedConfig(t) txStore = cltest.NewTestTxStore(t, db) - ethKeyStore = cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore = cltest.NewKeyStore(t, db).Eth() _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { @@ -1450,9 +1417,8 @@ func TestORM_GetTxInProgress(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("gets 0 in progress eth transaction", func(t *testing.T) { @@ -1470,18 +1436,27 @@ func TestORM_GetTxInProgress(t *testing.T) { }) } -func TestORM_GetNonFatalTransactions(t *testing.T) { +func TestORM_GetAbandonedTransactionsByBatch(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, enabled := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + enabledAddrs := []common.Address{enabled} + + t.Run("get 0 abandoned transactions", func(t *testing.T) { + txes, err := txStore.GetAbandonedTransactionsByBatch(testutils.Context(t), ethClient.ConfiguredChainID(), enabledAddrs, 0, 10) + require.NoError(t, err) + require.Empty(t, txes) + }) - t.Run("gets 0 non finalized eth transaction", func(t *testing.T) { - txes, err := txStore.GetNonFatalTransactions(testutils.Context(t), ethClient.ConfiguredChainID()) + t.Run("do not return enabled addresses", func(t *testing.T) { + _ = mustInsertInProgressEthTxWithAttempt(t, txStore, 123, enabled) + _ = mustCreateUnstartedGeneratedTx(t, txStore, enabled, ethClient.ConfiguredChainID()) + txes, err := txStore.GetAbandonedTransactionsByBatch(testutils.Context(t), ethClient.ConfiguredChainID(), enabledAddrs, 0, 10) require.NoError(t, err) require.Empty(t, txes) }) @@ -1490,22 +1465,40 @@ func TestORM_GetNonFatalTransactions(t *testing.T) { inProgressTx := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) unstartedTx := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, ethClient.ConfiguredChainID()) - txes, err := txStore.GetNonFatalTransactions(testutils.Context(t), ethClient.ConfiguredChainID()) + txes, err := txStore.GetAbandonedTransactionsByBatch(testutils.Context(t), ethClient.ConfiguredChainID(), enabledAddrs, 0, 10) require.NoError(t, err) + require.Len(t, txes, 2) for _, tx := range txes { require.True(t, tx.ID == inProgressTx.ID || tx.ID == unstartedTx.ID) } }) + + t.Run("get batches of transactions", func(t *testing.T) { + var batchSize uint = 10 + numTxes := 55 + for i := 0; i < numTxes; i++ { + _ = mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, ethClient.ConfiguredChainID()) + } + + allTxes := make([]*txmgr.Tx, 0) + err := sqlutil.Batch(func(offset, limit uint) (count uint, err error) { + batchTxes, err := txStore.GetAbandonedTransactionsByBatch(testutils.Context(t), ethClient.ConfiguredChainID(), enabledAddrs, offset, limit) + require.NoError(t, err) + allTxes = append(allTxes, batchTxes...) + return uint(len(batchTxes)), nil + }, batchSize) + require.NoError(t, err) + require.Len(t, allTxes, numTxes+2) + }) } func TestORM_GetTxByID(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("no transaction", func(t *testing.T) { @@ -1526,9 +1519,8 @@ func TestORM_GetFatalTransactions(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("gets 0 fatal eth transactions", func(t *testing.T) { @@ -1549,9 +1541,8 @@ func TestORM_HasInProgressTransaction(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1574,9 +1565,8 @@ func TestORM_CountUnconfirmedTransactions(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1595,9 +1585,8 @@ func TestORM_CountTransactionsByState(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress1 := cltest.MustInsertRandomKey(t, ethKeyStore) _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1616,9 +1605,8 @@ func TestORM_CountUnstartedTransactions(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1637,9 +1625,8 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1733,9 +1720,8 @@ func TestORM_CreateTransaction(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := newTxStore(t, db) - kst := cltest.NewKeyStore(t, db, cfg.Database()) + kst := cltest.NewKeyStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() @@ -1833,15 +1819,14 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := txmgr.NewTxStore(db, logger.Test(t)) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("does not prune if queue has not exceeded capacity-1", func(t *testing.T) { subject1 := uuid.New() - strategy1 := txmgrcommon.NewDropOldestStrategy(subject1, uint32(5), cfg.Database().DefaultQueryTimeout()) + strategy1 := txmgrcommon.NewDropOldestStrategy(subject1, uint32(5)) for i := 0; i < 5; i++ { mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy1)) } @@ -1850,7 +1835,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { t.Run("prunes if queue has exceeded capacity-1", func(t *testing.T) { subject2 := uuid.New() - strategy2 := txmgrcommon.NewDropOldestStrategy(subject2, uint32(3), cfg.Database().DefaultQueryTimeout()) + strategy2 := txmgrcommon.NewDropOldestStrategy(subject2, uint32(3)) for i := 0; i < 5; i++ { mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy2)) } @@ -1858,6 +1843,28 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { }) } +func TestORM_FindTxesWithAttemptsAndReceiptsByIdsAndState(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + txStore := cltest.NewTestTxStore(t, db) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() + ctx := testutils.Context(t) + + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) + + tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) + r := newEthReceipt(4, utils.NewHash(), tx.TxAttempts[0].Hash, 0x1) + _, err := txStore.InsertReceipt(ctx, &r.Receipt) + require.NoError(t, err) + + txes, err := txStore.FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx, []int64{tx.ID}, []txmgrtypes.TxState{txmgrcommon.TxConfirmed}, testutils.FixtureChainID) + require.NoError(t, err) + require.Len(t, txes, 1) + require.Len(t, txes[0].TxAttempts, 1) + require.Len(t, txes[0].TxAttempts[0].Receipts, 1) +} + func AssertCountPerSubject(t *testing.T, txStore txmgr.TestEvmTxStore, expected int64, subject uuid.UUID) { t.Helper() count, err := txStore.CountTxesByStateAndSubject(testutils.Context(t), "unstarted", subject) diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index 0a0ece4b90b..5b8e77a69cc 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 61c948c1ff4..be59d0130a4 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -672,7 +672,7 @@ func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int6 } // FindTxesWithAttemptsAndReceiptsByIdsAndState provides a mock function with given fields: ctx, ids, states, chainID -func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []big.Int, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { +func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Context, ids []int64, states []types.TxState, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, ids, states, chainID) if len(ret) == 0 { @@ -681,10 +681,10 @@ func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.C var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { return rf(ctx, ids, states, chainID) } - if rf, ok := ret.Get(0).(func(context.Context, []big.Int, []types.TxState, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + if rf, ok := ret.Get(0).(func(context.Context, []int64, []types.TxState, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { r0 = rf(ctx, ids, states, chainID) } else { if ret.Get(0) != nil { @@ -692,7 +692,7 @@ func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.C } } - if rf, ok := ret.Get(1).(func(context.Context, []big.Int, []types.TxState, *big.Int) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, []int64, []types.TxState, *big.Int) error); ok { r1 = rf(ctx, ids, states, chainID) } else { r1 = ret.Error(1) @@ -821,29 +821,29 @@ func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx con return r0, r1 } -// GetInProgressTxAttempts provides a mock function with given fields: ctx, address, chainID -func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address common.Address, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(ctx, address, chainID) +// GetAbandonedTransactionsByBatch provides a mock function with given fields: ctx, chainID, enabledAddrs, offset, limit +func (_m *EvmTxStore) GetAbandonedTransactionsByBatch(ctx context.Context, chainID *big.Int, enabledAddrs []common.Address, offset uint, limit uint) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, chainID, enabledAddrs, offset, limit) if len(ret) == 0 { - panic("no return value specified for GetInProgressTxAttempts") + panic("no return value specified for GetAbandonedTransactionsByBatch") } - var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(ctx, address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, []common.Address, uint, uint) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, chainID, enabledAddrs, offset, limit) } - if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(ctx, address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, []common.Address, uint, uint) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, chainID, enabledAddrs, offset, limit) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { - r1 = rf(ctx, address, chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int, []common.Address, uint, uint) error); ok { + r1 = rf(ctx, chainID, enabledAddrs, offset, limit) } else { r1 = ret.Error(1) } @@ -851,29 +851,29 @@ func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address commo return r0, r1 } -// GetNonFatalTransactions provides a mock function with given fields: ctx, chainID -func (_m *EvmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(ctx, chainID) +// GetInProgressTxAttempts provides a mock function with given fields: ctx, address, chainID +func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address common.Address, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { - panic("no return value specified for GetNonFatalTransactions") + panic("no return value specified for GetInProgressTxAttempts") } - var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(ctx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, address, chainID) } - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(ctx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, address, chainID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) + r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { - r1 = rf(ctx, chainID) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, address, chainID) } else { r1 = ret.Error(1) } diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 7918ed0e2ca..b3ce48b702c 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -15,7 +15,6 @@ import ( txmgrmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" ) @@ -44,9 +43,8 @@ func TestReaper_ReapTxes(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, from := cltest.MustInsertRandomKey(t, ethKeyStore) var nonce int64 diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 81a634a4d98..331e39d6ccf 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -30,9 +30,8 @@ func Test_EthResender_resendUnconfirmed(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logCfg := pgtest.NewQConfig(true) lggr := logger.Test(t) - ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {}) ccfg := evmtest.NewChainScopedConfig(t, cfg) @@ -101,9 +100,8 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - logCfg := pgtest.NewQConfig(true) lggr, o := logger.TestObserved(t, zapcore.DebugLevel) - ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // Set this to the smallest non-zero value possible for the attempt to be eligible for resend delay := commonconfig.MustNewDuration(1 * time.Nanosecond) @@ -149,7 +147,7 @@ func Test_EthResender_Start(t *testing.T) { c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1) }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ccfg := evmtest.NewChainScopedConfig(t, cfg) _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) lggr := logger.Test(t) diff --git a/core/chains/evm/txmgr/strategies_test.go b/core/chains/evm/txmgr/strategies_test.go index 19f5f197289..d7f4ceaf450 100644 --- a/core/chains/evm/txmgr/strategies_test.go +++ b/core/chains/evm/txmgr/strategies_test.go @@ -11,7 +11,6 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" ) func Test_SendEveryStrategy(t *testing.T) { @@ -28,10 +27,9 @@ func Test_SendEveryStrategy(t *testing.T) { func Test_DropOldestStrategy_Subject(t *testing.T) { t.Parallel() - cfg := configtest.NewGeneralConfig(t, nil) subject := uuid.New() - s := txmgrcommon.NewDropOldestStrategy(subject, 1, cfg.Database().DefaultQueryTimeout()) + s := txmgrcommon.NewDropOldestStrategy(subject, 1) assert.True(t, s.Subject().Valid) assert.Equal(t, subject, s.Subject().UUID) @@ -39,14 +37,12 @@ func Test_DropOldestStrategy_Subject(t *testing.T) { func Test_DropOldestStrategy_PruneQueue(t *testing.T) { t.Parallel() - cfg := configtest.NewGeneralConfig(t, nil) subject := uuid.New() queueSize := uint32(2) - queryTimeout := cfg.Database().DefaultQueryTimeout() mockTxStore := mocks.NewEvmTxStore(t) t.Run("calls PrineUnstartedTxQueue for the given subject and queueSize, ignoring fromAddress", func(t *testing.T) { - strategy1 := txmgrcommon.NewDropOldestStrategy(subject, queueSize, queryTimeout) + strategy1 := txmgrcommon.NewDropOldestStrategy(subject, queueSize) mockTxStore.On("PruneUnstartedTxQueue", mock.Anything, queueSize-1, subject, mock.Anything, mock.Anything).Once().Return([]int64{1, 2}, nil) ids, err := strategy1.PruneQueue(testutils.Context(t), mockTxStore) require.NoError(t, err) diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index e95c005dc77..a0503253591 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -1,7 +1,6 @@ package txmgr_test import ( - "context" "math/big" "testing" "time" @@ -10,6 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -22,9 +22,8 @@ const waitTime = 5 * time.Millisecond func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, keystore.Eth, []common.Address) { db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() chainID := big.NewInt(0) var enabledAddresses []common.Address _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore, *ubig.NewI(chainID.Int64())) @@ -44,25 +43,23 @@ func containsID(txes []*txmgr.Tx, id int64) bool { } func TestEvmTracker_Initialization(t *testing.T) { - t.Skip("BCI-2638 tracker disabled") t.Parallel() tracker, _, _, _ := newTestEvmTrackerSetup(t) + ctx := testutils.Context(t) - err := tracker.Start(context.Background()) - require.NoError(t, err) + require.NoError(t, tracker.Start(ctx)) require.True(t, tracker.IsStarted()) t.Run("stop tracker", func(t *testing.T) { - err := tracker.Close() - require.NoError(t, err) + require.NoError(t, tracker.Close()) require.False(t, tracker.IsStarted()) }) } func TestEvmTracker_AddressTracking(t *testing.T) { - t.Skip("BCI-2638 tracker disabled") t.Parallel() + ctx := testutils.Context(t) t.Run("track abandoned addresses", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -76,33 +73,37 @@ func TestEvmTracker_AddressTracking(t *testing.T) { _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) _ = mustCreateUnstartedTx(t, txStore, unstartedAddr, cltest.MustGenerateRandomKey(t).Address, []byte{}, 0, big.Int{}, ethClient.ConfiguredChainID()) - err := tracker.Start(context.Background()) + err := tracker.Start(ctx) require.NoError(t, err) defer func(tracker *txmgr.Tracker) { err = tracker.Close() require.NoError(t, err) }(tracker) + time.Sleep(waitTime) addrs := tracker.GetAbandonedAddresses() require.NotContains(t, addrs, inProgressAddr) require.NotContains(t, addrs, unstartedAddr) - require.Contains(t, addrs, confirmedAddr) require.Contains(t, addrs, unconfirmedAddr) }) + /* TODO: finalized tx state https://smartcontract-it.atlassian.net/browse/BCI-2920 t.Run("stop tracking finalized tx", func(t *testing.T) { - t.Skip("BCI-2638 tracker disabled") tracker, txStore, _, _ := newTestEvmTrackerSetup(t) confirmedAddr := cltest.MustGenerateRandomKey(t).Address _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) - err := tracker.Start(context.Background()) + err := tracker.Start(ctx) require.NoError(t, err) defer func(tracker *txmgr.Tracker) { err = tracker.Close() require.NoError(t, err) }(tracker) + // deliver block before minConfirmations + tracker.XXXDeliverBlock(1) + time.Sleep(waitTime) + addrs := tracker.GetAbandonedAddresses() require.Contains(t, addrs, confirmedAddr) @@ -113,26 +114,12 @@ func TestEvmTracker_AddressTracking(t *testing.T) { addrs = tracker.GetAbandonedAddresses() require.NotContains(t, addrs, confirmedAddr) }) + */ } func TestEvmTracker_ExceedingTTL(t *testing.T) { - t.Skip("BCI-2638 tracker disabled") t.Parallel() - - t.Run("confirmed but unfinalized transaction still tracked", func(t *testing.T) { - tracker, txStore, _, _ := newTestEvmTrackerSetup(t) - addr1 := cltest.MustGenerateRandomKey(t).Address - _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, addr1, 123, 1) - - err := tracker.Start(context.Background()) - require.NoError(t, err) - defer func(tracker *txmgr.Tracker) { - err = tracker.Close() - require.NoError(t, err) - }(tracker) - - require.Contains(t, tracker.GetAbandonedAddresses(), addr1) - }) + ctx := testutils.Context(t) t.Run("exceeding ttl", func(t *testing.T) { tracker, txStore, _, _ := newTestEvmTrackerSetup(t) @@ -142,17 +129,17 @@ func TestEvmTracker_ExceedingTTL(t *testing.T) { tx2 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 123, addr2) tracker.XXXTestSetTTL(time.Nanosecond) - err := tracker.Start(context.Background()) + err := tracker.Start(ctx) require.NoError(t, err) defer func(tracker *txmgr.Tracker) { err = tracker.Close() require.NoError(t, err) }(tracker) - time.Sleep(waitTime) + time.Sleep(100 * waitTime) require.NotContains(t, tracker.GetAbandonedAddresses(), addr1, addr2) - fatalTxes, err := txStore.GetFatalTransactions(context.Background()) + fatalTxes, err := txStore.GetFatalTransactions(ctx) require.NoError(t, err) require.True(t, containsID(fatalTxes, tx1.ID)) require.True(t, containsID(fatalTxes, tx2.ID)) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index c3fbd75163e..aac9d89c490 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -93,7 +93,7 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() + keyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore) @@ -108,9 +108,8 @@ func TestTxm_CreateTransaction(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - kst := cltest.NewKeyStore(t, db, cfg.Database()) + kst := cltest.NewKeyStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() @@ -388,9 +387,8 @@ func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - etKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + etKeyStore := cltest.NewKeyStore(t, db).Eth() thisKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) otherKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) @@ -529,7 +527,7 @@ func TestTxm_Reset(t *testing.T) { db := pgtest.NewSqlxDB(t) gcfg := configtest.NewTestGeneralConfig(t) cfg := evmtest.NewChainScopedConfig(t, gcfg) - kst := cltest.NewKeyStore(t, db, cfg.Database()) + kst := cltest.NewKeyStore(t, db) _, addr := cltest.RandomKey{}.MustInsert(t, kst.Eth()) _, addr2 := cltest.RandomKey{}.MustInsert(t, kst.Eth()) @@ -550,7 +548,7 @@ func TestTxm_Reset(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(44), nil).Maybe() estimator := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), cfg.Database(), cfg.Database().Listener(), kst.Eth()) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), gcfg.Database(), gcfg.Database().Listener(), kst.Eth()) require.NoError(t, err) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, addr2) diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 38dbfa76a0a..ef355a01bda 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -25,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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" ) @@ -93,8 +92,7 @@ func TestEthTx_GetID(t *testing.T) { func TestEthTxAttempt_GetSignedTx(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) tx := cltest.NewLegacyTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index efa72133abf..920532518ab 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -206,7 +206,7 @@ func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayExt if !chain.IsEnabled() { return nil, errChainDisabled{ChainID: chainID} } - cfg := evmconfig.NewTOMLChainScopedConfig(opts.AppConfig, chain, l) + cfg := evmconfig.NewTOMLChainScopedConfig(chain, l) // note: per-chain validation is not necessary at this point since everything is checked earlier on boot. return newChain(ctx, cfg, chain.Nodes, opts) } @@ -215,7 +215,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod chainID := cfg.EVM().ChainID() l := opts.Logger var client evmclient.Client - if !cfg.EVMRPCEnabled() { + if !opts.AppConfig.EVMRPCEnabled() { client = evmclient.NewNullClient(chainID, l) } else if opts.GenEthClient == nil { client = evmclient.NewEvmClient(cfg.EVM().NodePool(), cfg.EVM(), cfg.EVM().NodePool().Errors(), l, chainID, nodes) @@ -226,7 +226,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod headBroadcaster := headtracker.NewHeadBroadcaster(l) headSaver := headtracker.NullSaver var headTracker httypes.HeadTracker - if !cfg.EVMRPCEnabled() { + if !opts.AppConfig.EVMRPCEnabled() { headTracker = headtracker.NullTracker } else if opts.GenHeadTracker == nil { orm := headtracker.NewORM(*chainID, opts.DB) @@ -237,7 +237,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod } logPoller := logpoller.LogPollerDisabled - if cfg.Feature().LogPoller() { + if opts.AppConfig.Feature().LogPoller() { if opts.GenLogPoller != nil { logPoller = opts.GenLogPoller(chainID) } else { @@ -256,7 +256,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod } // note: gas estimator is started as a part of the txm - txm, gasEstimator, err := newEvmTxm(opts.SqlxDB, opts.DB, cfg.EVM(), cfg.EVMRPCEnabled(), cfg.Database(), cfg.Database().Listener(), client, l, logPoller, opts) + txm, gasEstimator, err := newEvmTxm(opts.SqlxDB, opts.DB, cfg.EVM(), opts.AppConfig.EVMRPCEnabled(), opts.AppConfig.Database(), opts.AppConfig.Database().Listener(), client, l, logPoller, opts) if err != nil { return nil, fmt.Errorf("failed to instantiate EvmTxm for chain with ID %s: %w", chainID.String(), err) } @@ -270,13 +270,13 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod } var balanceMonitor monitor.BalanceMonitor - if cfg.EVMRPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() { + if opts.AppConfig.EVMRPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() { balanceMonitor = monitor.NewBalanceMonitor(client, opts.KeyStore, l) headBroadcaster.Subscribe(balanceMonitor) } var logBroadcaster log.Broadcaster - if !cfg.EVMRPCEnabled() { + if !opts.AppConfig.EVMRPCEnabled() { logBroadcaster = &log.NullBroadcaster{ErrMsg: fmt.Sprintf("Ethereum is disabled for chain %d", chainID)} } else if opts.GenLogBroadcaster == nil { logORM := log.NewORM(opts.SqlxDB, *chainID) diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index 87bdccf1891..8f313ee45ef 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/chains/legacyevm/mocks/legacy_chain_container.go b/core/chains/legacyevm/mocks/legacy_chain_container.go index 812b95d3697..527544de60d 100644 --- a/core/chains/legacyevm/mocks/legacy_chain_container.go +++ b/core/chains/legacyevm/mocks/legacy_chain_container.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/cmd/cosmos_keys_commands_test.go b/core/cmd/cosmos_keys_commands_test.go index 16609daadc6..7c3b4ed19f7 100644 --- a/core/cmd/cosmos_keys_commands_test.go +++ b/core/cmd/cosmos_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "flag" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -58,18 +60,20 @@ func TestShell_CosmosKeys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().Cosmos() cleanup := func() { + ctx := context.Background() keys, err := ks.GetAll() require.NoError(t, err) for _, key := range keys { - require.NoError(t, utils.JustError(ks.Delete(key.ID()))) + require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) } requireCosmosKeyCount(t, app, 0) } t.Run("ListCosmosKeys", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().Cosmos().Create() + key, err := app.GetKeyStore().Cosmos().Create(ctx) require.NoError(t, err) requireCosmosKeyCount(t, app, 1) assert.Nil(t, cmd.NewCosmosKeysClient(client).ListKeys(cltest.EmptyCLIContext())) @@ -90,8 +94,9 @@ func TestShell_CosmosKeys(t *testing.T) { t.Run("DeleteCosmosKey", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().Cosmos().Create() + key, err := app.GetKeyStore().Cosmos().Create(ctx) require.NoError(t, err) requireCosmosKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) @@ -110,9 +115,10 @@ func TestShell_CosmosKeys(t *testing.T) { t.Run("ImportExportCosmosKey", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(t) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().Cosmos().Create() + _, err := app.GetKeyStore().Cosmos().Create(ctx) require.NoError(t, err) keys := requireCosmosKeyCount(t, app, 1) @@ -146,7 +152,7 @@ func TestShell_CosmosKeys(t *testing.T) { require.NoError(t, tclient.ExportKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().Cosmos().Delete(key.ID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().Cosmos().Delete(ctx, key.ID()))) requireCosmosKeyCount(t, app, 0) set = flag.NewFlagSet("test Cosmos import", 0) diff --git a/core/cmd/cosmos_transaction_commands_test.go b/core/cmd/cosmos_transaction_commands_test.go index 5b5454eed44..c3e6a048103 100644 --- a/core/cmd/cosmos_transaction_commands_test.go +++ b/core/cmd/cosmos_transaction_commands_test.go @@ -40,6 +40,7 @@ func TestMain(m *testing.M) { } func TestShell_SendCosmosCoins(t *testing.T) { + ctx := testutils.Context(t) // TODO(BCI-978): cleanup once SetupLocalCosmosNode is updated chainID := cosmostest.RandomChainID() cosmosChain := coscfg.Chain{} @@ -57,7 +58,7 @@ func TestShell_SendCosmosCoins(t *testing.T) { from := accounts[0] to := accounts[1] - require.NoError(t, app.GetKeyStore().Cosmos().Add(cosmoskey.Raw(from.PrivateKey.Bytes()).Key())) + require.NoError(t, app.GetKeyStore().Cosmos().Add(ctx, cosmoskey.Raw(from.PrivateKey.Bytes()).Key())) chain, err := app.GetRelayers().LegacyCosmosChains().Get(chainID) require.NoError(t, err) diff --git a/core/cmd/csa_keys_commands_test.go b/core/cmd/csa_keys_commands_test.go index a181922979a..86e1b7d544f 100644 --- a/core/cmd/csa_keys_commands_test.go +++ b/core/cmd/csa_keys_commands_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -53,9 +54,10 @@ func TestCSAKeyPresenter_RenderTable(t *testing.T) { func TestShell_ListCSAKeys(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) - key, err := app.GetKeyStore().CSA().Create() + key, err := app.GetKeyStore().CSA().Create(ctx) require.NoError(t, err) requireCSAKeyCount(t, app, 1) @@ -85,11 +87,12 @@ func TestShell_ImportExportCsaKey(t *testing.T) { t.Parallel() defer deleteKeyExportFile(t) + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().CSA().Create() + _, err := app.GetKeyStore().CSA().Create(ctx) require.NoError(t, err) keys := requireCSAKeyCount(t, app, 1) @@ -122,7 +125,7 @@ func TestShell_ImportExportCsaKey(t *testing.T) { require.NoError(t, client.ExportCSAKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().CSA().Delete(key.ID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().CSA().Delete(ctx, key.ID()))) requireCSAKeyCount(t, app, 0) //Import test diff --git a/core/cmd/dkgencrypt_keys_commands_test.go b/core/cmd/dkgencrypt_keys_commands_test.go index b4c6d6f6e91..7b0de4f7774 100644 --- a/core/cmd/dkgencrypt_keys_commands_test.go +++ b/core/cmd/dkgencrypt_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "flag" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -58,18 +60,20 @@ func TestShell_DKGEncryptKeys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().DKGEncrypt() cleanup := func() { + ctx := context.Background() keys, err := ks.GetAll() assert.NoError(t, err) for _, key := range keys { - assert.NoError(t, utils.JustError(ks.Delete(key.ID()))) + assert.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) } requireDKGEncryptKeyCount(t, app, 0) } t.Run("ListDKGEncryptKeys", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGEncrypt().Create() + key, err := app.GetKeyStore().DKGEncrypt().Create(ctx) assert.NoError(tt, err) requireDKGEncryptKeyCount(t, app, 1) assert.Nil(t, cmd.NewDKGEncryptKeysClient(client).ListKeys(cltest.EmptyCLIContext())) @@ -89,8 +93,9 @@ func TestShell_DKGEncryptKeys(t *testing.T) { t.Run("DeleteDKGEncryptKey", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGEncrypt().Create() + key, err := app.GetKeyStore().DKGEncrypt().Create(ctx) assert.NoError(tt, err) requireDKGEncryptKeyCount(tt, app, 1) set := flag.NewFlagSet("test", 0) @@ -110,9 +115,10 @@ func TestShell_DKGEncryptKeys(t *testing.T) { t.Run("ImportExportDKGEncryptKey", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(tt) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().DKGEncrypt().Create() + _, err := app.GetKeyStore().DKGEncrypt().Create(ctx) require.NoError(tt, err) keys := requireDKGEncryptKeyCount(tt, app, 1) @@ -146,7 +152,7 @@ func TestShell_DKGEncryptKeys(t *testing.T) { require.NoError(tt, cmd.NewDKGEncryptKeysClient(client).ExportKey(c)) require.NoError(tt, utils.JustError(os.Stat(keyName))) - require.NoError(tt, utils.JustError(app.GetKeyStore().DKGEncrypt().Delete(key.ID()))) + require.NoError(tt, utils.JustError(app.GetKeyStore().DKGEncrypt().Delete(ctx, key.ID()))) requireDKGEncryptKeyCount(tt, app, 0) //Import test diff --git a/core/cmd/dkgsign_keys_commands_test.go b/core/cmd/dkgsign_keys_commands_test.go index 717f988b328..777e8a0a3c3 100644 --- a/core/cmd/dkgsign_keys_commands_test.go +++ b/core/cmd/dkgsign_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "flag" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -58,18 +60,20 @@ func TestShell_DKGSignKeys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().DKGSign() cleanup := func() { + ctx := context.Background() keys, err := ks.GetAll() assert.NoError(t, err) for _, key := range keys { - assert.NoError(t, utils.JustError(ks.Delete(key.ID()))) + assert.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) } requireDKGSignKeyCount(t, app, 0) } t.Run("ListDKGSignKeys", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGSign().Create() + key, err := app.GetKeyStore().DKGSign().Create(ctx) assert.NoError(tt, err) requireDKGSignKeyCount(t, app, 1) assert.Nil(t, cmd.NewDKGSignKeysClient(client).ListKeys(cltest.EmptyCLIContext())) @@ -89,8 +93,9 @@ func TestShell_DKGSignKeys(t *testing.T) { t.Run("DeleteDKGSignKey", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGSign().Create() + key, err := app.GetKeyStore().DKGSign().Create(ctx) assert.NoError(tt, err) requireDKGSignKeyCount(tt, app, 1) set := flag.NewFlagSet("test", 0) @@ -109,9 +114,10 @@ func TestShell_DKGSignKeys(t *testing.T) { t.Run("ImportExportDKGSignKey", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(tt) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().DKGSign().Create() + _, err := app.GetKeyStore().DKGSign().Create(ctx) require.NoError(tt, err) keys := requireDKGSignKeyCount(tt, app, 1) @@ -145,7 +151,7 @@ func TestShell_DKGSignKeys(t *testing.T) { require.NoError(tt, cmd.NewDKGSignKeysClient(client).ExportKey(c)) require.NoError(tt, utils.JustError(os.Stat(keyName))) - require.NoError(tt, utils.JustError(app.GetKeyStore().DKGSign().Delete(key.ID()))) + require.NoError(tt, utils.JustError(app.GetKeyStore().DKGSign().Delete(ctx, key.ID()))) requireDKGSignKeyCount(tt, app, 0) set = flag.NewFlagSet("test DKGSign import", 0) diff --git a/core/cmd/key_store_authenticator.go b/core/cmd/key_store_authenticator.go index 0707aa5087d..6ad4b0ef2ba 100644 --- a/core/cmd/key_store_authenticator.go +++ b/core/cmd/key_store_authenticator.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "fmt" "strings" @@ -20,8 +21,8 @@ type keystorePassword interface { Keystore() string } -func (auth TerminalKeyStoreAuthenticator) authenticate(keyStore keystore.Master, password keystorePassword) error { - isEmpty, err := keyStore.IsEmpty() +func (auth TerminalKeyStoreAuthenticator) authenticate(ctx context.Context, keyStore keystore.Master, password keystorePassword) error { + isEmpty, err := keyStore.IsEmpty(ctx) if err != nil { return errors.Wrap(err, "error determining if keystore is empty") } @@ -34,7 +35,7 @@ func (auth TerminalKeyStoreAuthenticator) authenticate(keyStore keystore.Master, if err = auth.validatePasswordStrength(pw); err != nil && isEmpty { return err } - return keyStore.Unlock(pw) + return keyStore.Unlock(ctx, pw) } interactive := auth.Prompter.IsTerminal() if !interactive { @@ -47,7 +48,7 @@ func (auth TerminalKeyStoreAuthenticator) authenticate(keyStore keystore.Master, if err != nil { return err } - return keyStore.Unlock(pw) + return keyStore.Unlock(ctx, pw) } func (auth TerminalKeyStoreAuthenticator) validatePasswordStrength(password string) error { diff --git a/core/cmd/mocks/prompter.go b/core/cmd/mocks/prompter.go index a05d24d671b..38c1d327fb3 100644 --- a/core/cmd/mocks/prompter.go +++ b/core/cmd/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/cmd/ocr2_keys_commands_test.go b/core/cmd/ocr2_keys_commands_test.go index eff44685612..b0c62f01aa5 100644 --- a/core/cmd/ocr2_keys_commands_test.go +++ b/core/cmd/ocr2_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "encoding/hex" "flag" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -71,19 +73,21 @@ func TestShell_OCR2Keys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().OCR2() cleanup := func() { + ctx := context.Background() keys, err := app.GetKeyStore().OCR2().GetAll() require.NoError(t, err) for _, key := range keys { - require.NoError(t, ks.Delete(key.ID())) + require.NoError(t, ks.Delete(ctx, key.ID())) } requireOCR2KeyCount(t, app, 0) } t.Run("ListOCR2KeyBundles", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().OCR2().Create("evm") + key, err := app.GetKeyStore().OCR2().Create(ctx, "evm") require.NoError(t, err) requireOCR2KeyCount(t, app, 1) assert.Nil(t, client.ListOCR2KeyBundles(cltest.EmptyCLIContext())) @@ -113,9 +117,10 @@ func TestShell_OCR2Keys(t *testing.T) { t.Run("DeleteOCR2KeyBundle", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().OCR2().Create("evm") + key, err := app.GetKeyStore().OCR2().Create(ctx, "evm") require.NoError(t, err) requireOCR2KeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) @@ -136,9 +141,10 @@ func TestShell_OCR2Keys(t *testing.T) { t.Run("ImportExportOCR2Key", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(t) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - err := app.KeyStore.OCR2().Add(cltest.DefaultOCR2Key) + err := app.KeyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key) require.NoError(t, err) keys := requireOCR2KeyCount(t, app, 1) @@ -171,7 +177,7 @@ func TestShell_OCR2Keys(t *testing.T) { require.NoError(t, client.ExportOCR2Key(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, app.GetKeyStore().OCR2().Delete(key.ID())) + require.NoError(t, app.GetKeyStore().OCR2().Delete(ctx, key.ID())) requireOCR2KeyCount(t, app, 0) set = flag.NewFlagSet("test OCR2 import", 0) diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index 1f9e3f0bc98..7f5b0321480 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -352,7 +352,7 @@ func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, chainID int64, e } func setupKeystore(ctx context.Context, cli *Shell, app chainlink.Application, keyStore keystore.Master) error { - if err := cli.KeyStoreAuthenticator.authenticate(keyStore, cli.Config.Password()); err != nil { + if err := cli.KeyStoreAuthenticator.authenticate(ctx, keyStore, cli.Config.Password()); err != nil { return errors.Wrap(err, "error authenticating keystore") } @@ -382,19 +382,19 @@ func setupKeystore(ctx context.Context, cli *Shell, app chainlink.Application, k enabledChains = append(enabledChains, chaintype.StarkNet) } - if err := keyStore.OCR2().EnsureKeys(enabledChains...); err != nil { + if err := keyStore.OCR2().EnsureKeys(ctx, enabledChains...); err != nil { return errors.Wrap(err, "failed to ensure ocr key") } - if err := keyStore.DKGSign().EnsureKey(); err != nil { + if err := keyStore.DKGSign().EnsureKey(ctx); err != nil { return errors.Wrap(err, "failed to ensure dkgsign key") } - if err := keyStore.DKGEncrypt().EnsureKey(); err != nil { + if err := keyStore.DKGEncrypt().EnsureKey(ctx); err != nil { return errors.Wrap(err, "failed to ensure dkgencrypt key") } - if err := keyStore.P2P().EnsureKey(); err != nil { + if err := keyStore.P2P().EnsureKey(ctx); err != nil { return errors.Wrap(err, "failed to ensure p2p key") } diff --git a/core/cmd/ocr_keys_commands_test.go b/core/cmd/ocr_keys_commands_test.go index f5da3294903..42d7451edbe 100644 --- a/core/cmd/ocr_keys_commands_test.go +++ b/core/cmd/ocr_keys_commands_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -65,11 +66,12 @@ func TestOCRKeyBundlePresenter_RenderTable(t *testing.T) { func TestShell_ListOCRKeyBundles(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().OCR().Create() + key, err := app.GetKeyStore().OCR().Create(ctx) require.NoError(t, err) requireOCRKeyCount(t, app, 1) @@ -101,11 +103,12 @@ func TestShell_CreateOCRKeyBundle(t *testing.T) { func TestShell_DeleteOCRKeyBundle(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().OCR().Create() + key, err := app.GetKeyStore().OCR().Create(ctx) require.NoError(t, err) requireOCRKeyCount(t, app, 1) @@ -128,11 +131,12 @@ func TestShell_DeleteOCRKeyBundle(t *testing.T) { func TestShell_ImportExportOCRKey(t *testing.T) { defer deleteKeyExportFile(t) + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) keys := requireOCRKeyCount(t, app, 1) key := keys[0] @@ -164,7 +168,7 @@ func TestShell_ImportExportOCRKey(t *testing.T) { require.NoError(t, client.ExportOCRKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().OCR().Delete(key.ID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().OCR().Delete(ctx, key.ID()))) requireOCRKeyCount(t, app, 0) set = flag.NewFlagSet("test OCR import", 0) diff --git a/core/cmd/p2p_keys_commands_test.go b/core/cmd/p2p_keys_commands_test.go index 87269e02711..12d22e7c16b 100644 --- a/core/cmd/p2p_keys_commands_test.go +++ b/core/cmd/p2p_keys_commands_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -61,9 +62,10 @@ func TestP2PKeyPresenter_RenderTable(t *testing.T) { func TestShell_ListP2PKeys(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) - key, err := app.GetKeyStore().P2P().Create() + key, err := app.GetKeyStore().P2P().Create(ctx) require.NoError(t, err) requireP2PKeyCount(t, app, 1) @@ -92,11 +94,12 @@ func TestShell_CreateP2PKey(t *testing.T) { func TestShell_DeleteP2PKey(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().P2P().Create() + key, err := app.GetKeyStore().P2P().Create(ctx) require.NoError(t, err) requireP2PKeyCount(t, app, 1) @@ -118,12 +121,13 @@ func TestShell_DeleteP2PKey(t *testing.T) { func TestShell_ImportExportP2PKeyBundle(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) defer deleteKeyExportFile(t) app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().P2P().Create() + _, err := app.GetKeyStore().P2P().Create(ctx) require.NoError(t, err) keys := requireP2PKeyCount(t, app, 1) @@ -156,7 +160,7 @@ func TestShell_ImportExportP2PKeyBundle(t *testing.T) { require.NoError(t, client.ExportP2PKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().P2P().Delete(key.PeerID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().P2P().Delete(ctx, key.PeerID()))) requireP2PKeyCount(t, app, 0) set = flag.NewFlagSet("test P2P import", 0) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index de84ed401a6..bc58c5cab6d 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -154,7 +154,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G return nil, err } - keyStore := keystore.New(sqlxDB, utils.GetScryptParams(cfg), appLggr, cfg.Database()) + keyStore := keystore.New(db, utils.GetScryptParams(cfg), appLggr) mailMon := mailbox.NewMonitor(cfg.AppID().String(), appLggr.Named("Mailbox")) loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 9baeb3f5496..a61390a4886 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -364,7 +364,7 @@ func (s *Shell) runNode(c *cli.Context) error { // Local shell initialization always uses local auth users table for admin auth authProviderORM := app.BasicAdminUsersORM() keyStore := app.GetKeyStore() - err = s.KeyStoreAuthenticator.authenticate(keyStore, s.Config.Password()) + err = s.KeyStoreAuthenticator.authenticate(rootCtx, keyStore, s.Config.Password()) if err != nil { return errors.Wrap(err, "error authenticating keystore") } @@ -390,7 +390,7 @@ func (s *Shell) runNode(c *cli.Context) error { } if s.Config.OCR().Enabled() { - err2 := app.GetKeyStore().OCR().EnsureKey() + err2 := app.GetKeyStore().OCR().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure ocr key") } @@ -409,37 +409,37 @@ func (s *Shell) runNode(c *cli.Context) error { if s.Config.StarkNetEnabled() { enabledChains = append(enabledChains, chaintype.StarkNet) } - err2 := app.GetKeyStore().OCR2().EnsureKeys(enabledChains...) + err2 := app.GetKeyStore().OCR2().EnsureKeys(rootCtx, enabledChains...) if err2 != nil { return errors.Wrap(err2, "failed to ensure ocr key") } } if s.Config.P2P().Enabled() { - err2 := app.GetKeyStore().P2P().EnsureKey() + err2 := app.GetKeyStore().P2P().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure p2p key") } } if s.Config.CosmosEnabled() { - err2 := app.GetKeyStore().Cosmos().EnsureKey() + err2 := app.GetKeyStore().Cosmos().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure cosmos key") } } if s.Config.SolanaEnabled() { - err2 := app.GetKeyStore().Solana().EnsureKey() + err2 := app.GetKeyStore().Solana().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure solana key") } } if s.Config.StarkNetEnabled() { - err2 := app.GetKeyStore().StarkNet().EnsureKey() + err2 := app.GetKeyStore().StarkNet().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure starknet key") } } - err2 := app.GetKeyStore().CSA().EnsureKey() + err2 := app.GetKeyStore().CSA().EnsureKey(rootCtx) if err2 != nil { return errors.Wrap(err2, "failed to ensure CSA key") } @@ -621,7 +621,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { return s.errorOut(fmt.Errorf("error validating configuration: %+v", err)) } - err = keyStore.Unlock(s.Config.Password().Keystore()) + err = keyStore.Unlock(ctx, s.Config.Password().Keystore()) if err != nil { return s.errorOut(errors.Wrap(err, "error authenticating keystore")) } @@ -637,7 +637,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { cfg := txmgr.NewEvmTxmConfig(chain.Config().EVM()) feeCfg := txmgr.NewEvmTxmFeeConfig(chain.Config().EVM().GasEstimator()) ec := txmgr.NewEvmConfirmer(orm, txmgr.NewEvmTxmClient(ethClient, chain.Config().EVM().NodePool().Errors()), - cfg, feeCfg, chain.Config().EVM().Transactions(), chain.Config().Database(), keyStore.Eth(), txBuilder, chain.Logger()) + cfg, feeCfg, chain.Config().EVM().Transactions(), app.GetConfig().Database(), keyStore.Eth(), txBuilder, chain.Logger()) totalNonces := endingNonce - beginningNonce + 1 nonces := make([]evmtypes.Nonce, totalNonces) for i := int64(0); i < totalNonces; i++ { diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 6ac401e906c..d608d3931d0 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -80,7 +80,7 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { c.Insecure.OCRDevelopmentMode = nil }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) authProviderORM := localauth.NewORM(db, time.Minute, logger.TestLogger(t), audit.NoopLogger) lggr := logger.TestLogger(t) @@ -181,7 +181,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { // create/run with a new admin user pgtest.MustExec(t, db, "DELETE FROM users;") - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) _, err := keyStore.Eth().Create(testutils.Context(t), &cltest.FixtureChainID) require.NoError(t, err) @@ -290,7 +290,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { // seems to be needed for config validate c.Insecure.OCRDevelopmentMode = nil }) - keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) + keyStore := cltest.NewKeyStore(t, sqlxDB) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) txStore := cltest.NewTestTxStore(t, sqlxDB) @@ -302,6 +302,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { app.On("GetSqlxDB").Return(sqlxDB) app.On("GetKeyStore").Return(keyStore) app.On("ID").Maybe().Return(uuid.New()) + app.On("GetConfig").Return(config) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) @@ -370,7 +371,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { c.Insecure.OCRDevelopmentMode = nil }) - keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) + keyStore := cltest.NewKeyStore(t, sqlxDB) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -383,6 +384,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { app.On("GetSqlxDB").Return(sqlxDB) app.On("GetKeyStore").Return(keyStore) app.On("ID").Maybe().Return(uuid.New()) + app.On("GetConfig").Return(config) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("Dial", mock.Anything).Return(nil) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) @@ -446,7 +448,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { c.Insecure.OCRDevelopmentMode = nil }) - keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) + keyStore := cltest.NewKeyStore(t, sqlxDB) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -487,6 +489,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { if test.shouldError { require.ErrorContains(t, client.RebroadcastTransactions(c), test.errorContains) } else { + app.On("GetConfig").Return(config).Once() require.NoError(t, client.RebroadcastTransactions(c)) } diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 0d8d0b7b459..a8c054cd9be 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -565,6 +565,7 @@ func TestShell_ConfigV2(t *testing.T) { func TestShell_RunOCRJob_HappyPath(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.OCR.Enabled = ptr(true) @@ -577,7 +578,7 @@ func TestShell_RunOCRJob_HappyPath(t *testing.T) { }) client, _ := app.NewShellAndRenderer() - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) diff --git a/core/cmd/solana_keys_commands_test.go b/core/cmd/solana_keys_commands_test.go index d58c3657019..897031877c1 100644 --- a/core/cmd/solana_keys_commands_test.go +++ b/core/cmd/solana_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "flag" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -58,18 +60,20 @@ func TestShell_SolanaKeys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().Solana() cleanup := func() { + ctx := context.Background() keys, err := ks.GetAll() require.NoError(t, err) for _, key := range keys { - require.NoError(t, utils.JustError(ks.Delete(key.ID()))) + require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) } requireSolanaKeyCount(t, app, 0) } t.Run("ListSolanaKeys", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().Solana().Create() + key, err := app.GetKeyStore().Solana().Create(ctx) require.NoError(t, err) requireSolanaKeyCount(t, app, 1) assert.Nil(t, cmd.NewSolanaKeysClient(client).ListKeys(cltest.EmptyCLIContext())) @@ -90,8 +94,9 @@ func TestShell_SolanaKeys(t *testing.T) { t.Run("DeleteSolanaKey", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().Solana().Create() + key, err := app.GetKeyStore().Solana().Create(ctx) require.NoError(t, err) requireSolanaKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) @@ -111,9 +116,10 @@ func TestShell_SolanaKeys(t *testing.T) { t.Run("ImportExportSolanaKey", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(t) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().Solana().Create() + _, err := app.GetKeyStore().Solana().Create(ctx) require.NoError(t, err) keys := requireSolanaKeyCount(t, app, 1) @@ -146,7 +152,7 @@ func TestShell_SolanaKeys(t *testing.T) { require.NoError(t, cmd.NewSolanaKeysClient(client).ExportKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().Solana().Delete(key.ID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().Solana().Delete(ctx, key.ID()))) requireSolanaKeyCount(t, app, 0) set = flag.NewFlagSet("test Solana import", 0) diff --git a/core/cmd/solana_transaction_commands_test.go b/core/cmd/solana_transaction_commands_test.go index b190caec51b..c26bd89ab94 100644 --- a/core/cmd/solana_transaction_commands_test.go +++ b/core/cmd/solana_transaction_commands_test.go @@ -19,11 +19,13 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana" solanaClient "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/cmd" ) func TestShell_SolanaSendSol(t *testing.T) { + ctx := testutils.Context(t) chainID := "localnet" url := solanaClient.SetupLocalSolNode(t) node := solcfg.Node{ @@ -36,7 +38,7 @@ func TestShell_SolanaSendSol(t *testing.T) { Enabled: ptr(true), } app := solanaStartNewApplication(t, &cfg) - from, err := app.GetKeyStore().Solana().Create() + from, err := app.GetKeyStore().Solana().Create(ctx) require.NoError(t, err) to, err := solanago.NewRandomPrivateKey() require.NoError(t, err) diff --git a/core/cmd/starknet_keys_commands_test.go b/core/cmd/starknet_keys_commands_test.go index 0cf0065129d..5823a80b46d 100644 --- a/core/cmd/starknet_keys_commands_test.go +++ b/core/cmd/starknet_keys_commands_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "flag" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -57,18 +59,20 @@ func TestShell_StarkNetKeys(t *testing.T) { app := startNewApplicationV2(t, nil) ks := app.GetKeyStore().StarkNet() cleanup := func() { + ctx := context.Background() keys, err := ks.GetAll() require.NoError(t, err) for _, key := range keys { - require.NoError(t, utils.JustError(ks.Delete(key.ID()))) + require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) } requireStarkNetKeyCount(t, app, 0) } t.Run("ListStarkNetKeys", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().StarkNet().Create() + key, err := app.GetKeyStore().StarkNet().Create(ctx) require.NoError(t, err) requireStarkNetKeyCount(t, app, 1) assert.Nil(t, cmd.NewStarkNetKeysClient(client).ListKeys(cltest.EmptyCLIContext())) @@ -89,8 +93,9 @@ func TestShell_StarkNetKeys(t *testing.T) { t.Run("DeleteStarkNetKey", func(tt *testing.T) { defer cleanup() + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().StarkNet().Create() + key, err := app.GetKeyStore().StarkNet().Create(ctx) require.NoError(t, err) requireStarkNetKeyCount(t, app, 1) set := flag.NewFlagSet("test", 0) @@ -110,9 +115,10 @@ func TestShell_StarkNetKeys(t *testing.T) { t.Run("ImportExportStarkNetKey", func(tt *testing.T) { defer cleanup() defer deleteKeyExportFile(t) + ctx := testutils.Context(t) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().StarkNet().Create() + _, err := app.GetKeyStore().StarkNet().Create(ctx) require.NoError(t, err) keys := requireStarkNetKeyCount(t, app, 1) @@ -145,7 +151,7 @@ func TestShell_StarkNetKeys(t *testing.T) { require.NoError(t, cmd.NewStarkNetKeysClient(client).ExportKey(c)) require.NoError(t, utils.JustError(os.Stat(keyName))) - require.NoError(t, utils.JustError(app.GetKeyStore().StarkNet().Delete(key.ID()))) + require.NoError(t, utils.JustError(app.GetKeyStore().StarkNet().Delete(ctx, key.ID()))) requireStarkNetKeyCount(t, app, 0) set = flag.NewFlagSet("test StarkNet import", 0) diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go index 1a21c89e9ad..fb01cc29cd0 100644 --- a/core/config/mocks/telemetry_ingress.go +++ b/core/config/mocks/telemetry_ingress.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/config/mocks/telemetry_ingress_endpoint.go b/core/config/mocks/telemetry_ingress_endpoint.go index 08432cfe0ee..e5f8c3106eb 100644 --- a/core/config/mocks/telemetry_ingress_endpoint.go +++ b/core/config/mocks/telemetry_ingress_endpoint.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go b/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go index 177c35fcea7..1f6c763d280 100644 --- a/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go +++ b/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go @@ -57,7 +57,7 @@ type AutomationRegistrar23TriggerRegistrationStorage struct { } var AutomationRegistrarMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minRegistrationFees\",\"type\":\"uint256[]\"},{\"internalType\":\"contractIWrappedNative\",\"name\":\"wrappedNativeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidBillingToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"AutoApproveAllowedSenderSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"displayName\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"RegistrationApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"RegistrationRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RegistrationRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"}],\"name\":\"getAutoApproveAllowedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMinimumRegistrationAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_WRAPPED_NATIVE_TOKEN\",\"outputs\":[{\"internalType\":\"contractIWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minBalances\",\"type\":\"uint256[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"setTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"},{\"internalType\":\"contractIERC20Metadata[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minRegistrationFees\",\"type\":\"uint256[]\"},{\"internalType\":\"contractIWrappedNative\",\"name\":\"wrappedNativeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidBillingToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"AutoApproveAllowedSenderSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"displayName\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"RegistrationApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"RegistrationRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RegistrationRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"}],\"name\":\"getAutoApproveAllowedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMinimumRegistrationAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_WRAPPED_NATIVE_TOKEN\",\"outputs\":[{\"internalType\":\"contractIWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"internalType\":\"contractIERC20Metadata[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minBalances\",\"type\":\"uint256[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"setTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", Bin: "0x60c06040523480156200001157600080fd5b5060405162003483380380620034838339810160408190526200003491620005db565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000183565b5050506001600160a01b03808716608052811660a052620000e18584846200022e565b60005b84518110156200017657620001618582815181106200010757620001076200076d565b6020026020010151600001518683815181106200012857620001286200076d565b6020026020010151602001518784815181106200014957620001496200076d565b6020026020010151604001516200032a60201b60201c565b806200016d8162000783565b915050620000e4565b5050505050505062000804565b336001600160a01b03821603620001dd5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b62000238620003d8565b80518251146200025b57604051630dfe930960e41b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03851617905560005b8251811015620002fb578181815181106200029857620002986200076d565b602002602001015160046000858481518110620002b957620002b96200076d565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055508080620002f29062000783565b91505062000279565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b62000334620003d8565b60ff83166000908152600660205260409020805483919060ff19166001836002811115620003665762000366620007ab565b021790555060ff831660009081526006602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390620003cb90859085908590620007c1565b60405180910390a1505050565b6000546001600160a01b03163314620004345760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6001600160a01b03811681146200044c57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156200048a576200048a6200044f565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004bb57620004bb6200044f565b604052919050565b60006001600160401b03821115620004df57620004df6200044f565b5060051b60200190565b600082601f830112620004fb57600080fd5b81516020620005146200050e83620004c3565b62000490565b82815260059290921b840181019181810190868411156200053457600080fd5b8286015b848110156200055c5780516200054e8162000436565b835291830191830162000538565b509695505050505050565b600082601f8301126200057957600080fd5b815160206200058c6200050e83620004c3565b82815260059290921b84018101918181019086841115620005ac57600080fd5b8286015b848110156200055c5780518352918301918301620005b0565b8051620005d68162000436565b919050565b60008060008060008060c08789031215620005f557600080fd5b8651620006028162000436565b80965050602080880151620006178162000436565b60408901519096506001600160401b03808211156200063557600080fd5b818a0191508a601f8301126200064a57600080fd5b81516200065b6200050e82620004c3565b81815260609091028301840190848101908d8311156200067a57600080fd5b938501935b8285101562000701576060858f0312156200069a5760008081fd5b620006a462000465565b855160ff81168114620006b75760008081fd5b81528587015160038110620006cc5760008081fd5b81880152604086015163ffffffff81168114620006e95760008081fd5b6040820152825260609490940193908501906200067f565b60608d015190995094505050808311156200071b57600080fd5b620007298b848c01620004e9565b955060808a01519250808311156200074057600080fd5b50506200075089828a0162000567565b9250506200076160a08801620005c9565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060018201620007a457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff841681526060810160038410620007ea57634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b60805160a051612c2f620008546000396000818161027b015281816105a601526106390152600081816104b301528181610a0301528181610a6c0152818161168501526116dc0152612c2f6000f3fe6080604052600436106101295760003560e01c806388b12d55116100a5578063accb832311610074578063befdae4611610059578063befdae46146104a1578063c4d252f5146104d5578063f2fde38b146104f557600080fd5b8063accb832314610461578063b5ff5b411461048157600080fd5b806388b12d55146103085780638da5cb5b146103d3578063a2b1ff94146103fe578063a4c0ed361461044157600080fd5b80635ab1bd53116100fc5780636bf7d75f116100e15780636bf7d75f1461026957806379ba50971461029d5780637e776f7f146102b257600080fd5b80635ab1bd53146101fd57806366ab87f91461024957600080fd5b8063181f5a771461012e578063212d08841461018d5780632ce3a14a146101ba578063367b9b4f146101db575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e332e300000000000000081525081565b6040516101849190611e6f565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004611e9f565b610515565b6040516101849190611f24565b6101cd6101c836600461223b565b6105a2565b604051908152602001610184565b3480156101e757600080fd5b506101fb6101f636600461227e565b610710565b005b34801561020957600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561025557600080fd5b506101fb610264366004612346565b6107a2565b34801561027557600080fd5b506102247f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a957600080fd5b506101fb6108e9565b3480156102be57600080fd5b506102f86102cd36600461241c565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6040519015158152602001610184565b34801561031457600080fd5b5061039a610323366004612439565b6000908152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff169483018590526001909301549092169301929092529091565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610184565b3480156103df57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610224565b34801561040a57600080fd5b506101cd61041936600461241c565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561044d57600080fd5b506101fb61045c366004612452565b6109eb565b34801561046d57600080fd5b506101fb61047c3660046124db565b610b19565b34801561048d57600080fd5b506101fb61049c366004612526565b610c84565b3480156104ad57600080fd5b506102247f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e157600080fd5b506101fb6104f0366004612439565b610d63565b34801561050157600080fd5b506101fb61051036600461241c565b610f2a565b60408051606080820183526000808352602080840182905283850182905260ff86811683526006909152908490208451928301909452835492939192839116600281111561056557610565611eba565b600281111561057657610576611eba565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260a0015173ffffffffffffffffffffffffffffffffffffffff1614801561060257503415155b156106bd5761061034610f3e565b82602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561069f57600080fd5b505af11580156106b3573d6000803e3d6000fd5b5050505050610700565b610700333084602001516bffffffffffffffffffffffff168560a0015173ffffffffffffffffffffffffffffffffffffffff16610fe0909392919063ffffffff16565b61070a82336110c2565b92915050565b610718611529565b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6107aa611529565b80518251146107e5576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905560005b82518110156108ba578181815181106108435761084361256f565b6020026020010151600460008584815181106108615761086161256f565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555080806108b2906125cd565b915050610828565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461096f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a5a576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610a688284018461223b565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168160a0015173ffffffffffffffffffffffffffffffffffffffff1614610af3576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff84166020820152610b1181866110c2565b505050505050565b610b21611529565b6000818152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff16948301949094526001909201549092169282019290925290610bcd576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083604051602001610be091906126b9565b604051602081830303815290604052805190602001209050808314610c31576040517f3f4d605300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260056020526040812090815560010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610c7d610c7785612875565b826115ac565b5050505050565b610c8c611529565b60ff8316600090815260066020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610cd957610cd9611eba565b021790555060ff83166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610d5690859085908590612881565b60405180910390a1505050565b6000818152600560209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff16948301949094526001909201549092169282019290925290331480610dfd575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e33576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610e81576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320928355600190920180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905582519083015191830151610efb9273ffffffffffffffffffffffffffffffffffffffff90911691906bffffffffffffffffffffffff1661198f565b60405182907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a25050565b610f32611529565b610f3b816119ea565b50565b60006bffffffffffffffffffffffff821115610fdc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610966565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526110bc9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611adf565b50505050565b60a082015173ffffffffffffffffffffffffffffffffffffffff166000908152600460209081526040822054908401516bffffffffffffffffffffffff161015611138576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015173ffffffffffffffffffffffffffffffffffffffff16611189576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460a08401516040517fa538b2eb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015291169063a538b2eb90602401602060405180830381865afa1580156111fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122191906128ac565b611257576040517f1183afea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360405160200161126a91906128c9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600590935291205490915073ffffffffffffffffffffffffffffffffffffffff16156112fd576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836000015173ffffffffffffffffffffffffffffffffffffffff16817f7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b78660c001518760e00151886060015189604001518a608001518b61012001518c61014001518d61010001518e6020015160405161137f99989796959493929190612a35565b60405180910390a3608084015160ff908116600090815260066020526040808220815160608101909252805492936114029383911660028111156113c5576113c5611eba565b60028111156113d6576113d6611eba565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015285611beb565b1561146a57608085015160ff166000908152600660205260409020805465010000000000900463ffffffff1690600561143a83612af0565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061146385836115ac565b9050611521565b604080516060810182528682015173ffffffffffffffffffffffffffffffffffffffff90811682526020808901516bffffffffffffffffffffffff90811682850190815260a08b01518416858701908152600089815260059094529590922093519151167401000000000000000000000000000000000000000002908216178255915160019091018054919092167fffffffffffffffffffffffff0000000000000000000000000000000000000000919091161790555b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610966565b565b60025482516060840151604080860151608087015160a08801516101008901516101208a01516101408b015195517fc62cf68400000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff16988a988a9863c62cf6849861163c98939792969095939492939092909190600401612b13565b6020604051808303816000875af115801561165b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167f9190612ba1565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168660a0015173ffffffffffffffffffffffffffffffffffffffff16036117a6577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea08488602001518560405160200161172f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161175c93929190612bba565b6020604051808303816000875af115801561177b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179f91906128ac565b90506118fa565b60a086015160208701516040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526bffffffffffffffffffffffff909216602482015291169063095ea7b3906044016020604051808303816000875af1158015611833573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185791906128ac565b905080156118fa5760208601516040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff909116602482015273ffffffffffffffffffffffffffffffffffffffff84169063948108f790604401600060405180830381600087803b1580156118e157600080fd5b505af11580156118f5573d6000803e3d6000fd5b505050505b80611949576040517f39f1c8d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610966565b81857fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b8860c0015160405161197e9190611e6f565b60405180910390a350949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526119e59084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161103a565b505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610966565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611b41826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611c909092919063ffffffff16565b8051909150156119e55780806020019051810190611b5f91906128ac565b6119e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610966565b60008083516002811115611c0157611c01611eba565b03611c0e5750600061070a565b600183516002811115611c2357611c23611eba565b148015611c56575073ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16155b15611c635750600061070a565b826020015163ffffffff16836040015163ffffffff161015611c875750600161070a565b50600092915050565b60606115218484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051611cc49190612c06565b60006040518083038185875af1925050503d8060008114611d01576040519150601f19603f3d011682016040523d82523d6000602084013e611d06565b606091505b5091509150611d1787838387611d22565b979650505050505050565b60608315611db8578251600003611db15773ffffffffffffffffffffffffffffffffffffffff85163b611db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610966565b5081611521565b6115218383815115611dcd5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109669190611e6f565b60005b83811015611e1c578181015183820152602001611e04565b50506000910152565b60008151808452611e3d816020860160208601611e01565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611e826020830184611e25565b9392505050565b803560ff81168114611e9a57600080fd5b919050565b600060208284031215611eb157600080fd5b611e8282611e89565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110611f20577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000606082019050611f37828451611ee9565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715611fb057611fb0611f5d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611ffd57611ffd611f5d565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f3b57600080fd5b8035611e9a81612005565b80356bffffffffffffffffffffffff81168114611e9a57600080fd5b803563ffffffff81168114611e9a57600080fd5b600082601f83011261207357600080fd5b813567ffffffffffffffff81111561208d5761208d611f5d565b6120be60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611fb6565b8181528460208386010111156120d357600080fd5b816020850160208301376000918101602001919091529392505050565b6000610160828403121561210357600080fd5b61210b611f8c565b905061211682612027565b815261212460208301612032565b602082015261213560408301612027565b60408201526121466060830161204e565b606082015261215760808301611e89565b608082015261216860a08301612027565b60a082015260c082013567ffffffffffffffff8082111561218857600080fd5b61219485838601612062565b60c084015260e08401359150808211156121ad57600080fd5b6121b985838601612062565b60e0840152610100915081840135818111156121d457600080fd5b6121e086828701612062565b8385015250610120915081840135818111156121fb57600080fd5b61220786828701612062565b83850152506101409150818401358181111561222257600080fd5b61222e86828701612062565b8385015250505092915050565b60006020828403121561224d57600080fd5b813567ffffffffffffffff81111561226457600080fd5b611521848285016120f0565b8015158114610f3b57600080fd5b6000806040838503121561229157600080fd5b823561229c81612005565b915060208301356122ac81612270565b809150509250929050565b600067ffffffffffffffff8211156122d1576122d1611f5d565b5060051b60200190565b600082601f8301126122ec57600080fd5b813560206123016122fc836122b7565b611fb6565b82815260059290921b8401810191818101908684111561232057600080fd5b8286015b8481101561233b5780358352918301918301612324565b509695505050505050565b60008060006060848603121561235b57600080fd5b833561236681612005565b925060208481013567ffffffffffffffff8082111561238457600080fd5b818701915087601f83011261239857600080fd5b81356123a66122fc826122b7565b81815260059190911b8301840190848101908a8311156123c557600080fd5b938501935b828510156123ec5784356123dd81612005565b825293850193908501906123ca565b96505050604087013592508083111561240457600080fd5b5050612412868287016122db565b9150509250925092565b60006020828403121561242e57600080fd5b8135611e8281612005565b60006020828403121561244b57600080fd5b5035919050565b6000806000806060858703121561246857600080fd5b843561247381612005565b935060208501359250604085013567ffffffffffffffff8082111561249757600080fd5b818701915087601f8301126124ab57600080fd5b8135818111156124ba57600080fd5b8860208285010111156124cc57600080fd5b95989497505060200194505050565b600080604083850312156124ee57600080fd5b823567ffffffffffffffff81111561250557600080fd5b8301610160818603121561251857600080fd5b946020939093013593505050565b60008060006060848603121561253b57600080fd5b61254484611e89565b925060208401356003811061255857600080fd5b91506125666040850161204e565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036125fe576125fe61259e565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261263a57600080fd5b830160208101925035905067ffffffffffffffff81111561265a57600080fd5b80360382131561266957600080fd5b9250929050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526126e7602082016126cd84612027565b73ffffffffffffffffffffffffffffffffffffffff169052565b60006126f560208401612032565b6bffffffffffffffffffffffff811660408401525061271660408401612027565b73ffffffffffffffffffffffffffffffffffffffff811660608401525061273f6060840161204e565b63ffffffff811660808401525061275860808401611e89565b60ff811660a08401525061276e60a08401612027565b73ffffffffffffffffffffffffffffffffffffffff811660c08401525061279860c0840184612605565b6101608060e08601526127b061018086018385612670565b92506127bf60e0870187612605565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101008188870301818901526127f9868685612670565b9550612807818a018a612605565b9550925050610120818887030181890152612823868685612670565b9550612831818a018a612605565b955092505061014081888703018189015261284d868685612670565b955061285b818a018a612605565b955092505080878603018388015250611d17848483612670565b600061070a36836120f0565b60ff84168152606081016128986020830185611ee9565b63ffffffff83166040830152949350505050565b6000602082840312156128be57600080fd5b8151611e8281612270565b602081526128f060208201835173ffffffffffffffffffffffffffffffffffffffff169052565b6000602083015161291160408401826bffffffffffffffffffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015163ffffffff8116608084015250608083015160ff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c08301516101608060e0850152612993610180850183611e25565b915060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101008187860301818801526129d18584611e25565b9450808801519250506101208187860301818801526129f08584611e25565b945080880151925050610140818786030181880152612a0f8584611e25565b908801518782039092018488015293509050612a2b8382611e25565b9695505050505050565b6000610120808352612a498184018d611e25565b90508281036020840152612a5d818c611e25565b905063ffffffff8a16604084015273ffffffffffffffffffffffffffffffffffffffff8916606084015260ff8816608084015282810360a0840152612aa28188611e25565b905082810360c0840152612ab68187611e25565b905082810360e0840152612aca8186611e25565b9150506bffffffffffffffffffffffff83166101008301529a9950505050505050505050565b600063ffffffff808316818103612b0957612b0961259e565b6001019392505050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b166020850152808a16604085015260ff891660608501528088166080850152508060a0840152612b6a81840187611e25565b905082810360c0840152612b7e8186611e25565b905082810360e0840152612b928185611e25565b9b9a5050505050505050505050565b600060208284031215612bb357600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000612bfd6060830184611e25565b95945050505050565b60008251612c18818460208701611e01565b919091019291505056fea164736f6c6343000813000a", } diff --git a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go index c1d1edb04fb..891415c7d3a 100644 --- a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go @@ -34,6 +34,7 @@ type AutomationRegistryBase23BillingConfig struct { GasFeePPB uint32 FlatFeeMilliCents *big.Int PriceFeed common.Address + Decimals uint8 FallbackPrice *big.Int MinSpend *big.Int } @@ -44,7 +45,7 @@ type AutomationRegistryBase23BillingOverrides struct { } var AutomationRegistryLogicAMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_3\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_3\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Bin: "0x6101806040523480156200001257600080fd5b506040516200477c3803806200477c83398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e0516101005161012051610140516101605161406862000714600039600081816088015260de01526000505060005050600081816111bd01526114d60152600050506000505060005050600050506140686000f3fe608060405260043610620000865760003560e01c80638e86139b11620000555780638e86139b1462000192578063c62cf68414620001b7578063c804802214620001eb578063f2fde38b14620002105762000086565b8063349e8cca14620000ce57806379ba5097146200012857806385c1b0ba14620001405780638da5cb5b1462000165575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015620000c7573d6000f35b3d6000fd5b005b348015620000db57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156200013557600080fd5b50620000cc62000235565b3480156200014d57600080fd5b50620000cc6200015f36600462002cac565b62000338565b3480156200017257600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16620000fe565b3480156200019f57600080fd5b50620000cc620001b136600462002d85565b62001080565b348015620001c457600080fd5b50620001dc620001d636600462002f43565b62001408565b6040519081526020016200011f565b348015620001f857600080fd5b50620000cc6200020a36600462003038565b620017b5565b3480156200021d57600080fd5b50620000cc6200022f36600462003052565b62001c8d565b60015473ffffffffffffffffffffffffffffffffffffffff163314620002bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff16600381111562000377576200037762003079565b14158015620003c35750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff166003811115620003c057620003c062003079565b14155b15620003fb576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60165473ffffffffffffffffffffffffffffffffffffffff166200044b576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362000487576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290528190819060008667ffffffffffffffff811115620004f157620004f162002df0565b6040519080825280602002602001820160405280156200051b578160200160208202803683370190505b50905060008767ffffffffffffffff8111156200053c576200053c62002df0565b604051908082528060200260200182016040528015620005d357816020015b604080516101208101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816200055b5790505b50905060008867ffffffffffffffff811115620005f457620005f462002df0565b6040519080825280602002602001820160405280156200062957816020015b6060815260200190600190039081620006135790505b50905060008967ffffffffffffffff8111156200064a576200064a62002df0565b6040519080825280602002602001820160405280156200067f57816020015b6060815260200190600190039081620006695790505b50905060008a67ffffffffffffffff811115620006a057620006a062002df0565b604051908082528060200260200182016040528015620006d557816020015b6060815260200190600190039081620006bf5790505b50905060005b8b81101562000def578c8c82818110620006f957620006f9620030a8565b602090810292909201356000818152600484526040808220815161012081018352815460ff8082161515835261010080830490911615159883019890985263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e082015260029091015490911694810194909452909a5091985050819003620008305786610100015199508660c001516bffffffffffffffffffffffff1698505b8973ffffffffffffffffffffffffffffffffffffffff1687610100015173ffffffffffffffffffffffffffffffffffffffff1614620008f55773ffffffffffffffffffffffffffffffffffffffff8a166000908152602160205260409020546200089c908a9062003106565b73ffffffffffffffffffffffffffffffffffffffff8b16600081815260216020526040902091909155620008d2908c8b62001ca5565b86610100015199508660c001516bffffffffffffffffffffffff1698506200091e565b80156200091e5760c08701516200091b906bffffffffffffffffffffffff168a6200311c565b98505b620009298862001d39565b60808701516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200099957600080fd5b505af1158015620009ae573d6000803e3d6000fd5b5050505086858281518110620009c857620009c8620030a8565b60200260200101819052506005600089815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062000a1c5762000a1c620030a8565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526000898152600790915260409020805462000a5b9062003132565b80601f016020809104026020016040519081016040528092919081815260200182805462000a899062003132565b801562000ada5780601f1062000aae5761010080835404028352916020019162000ada565b820191906000526020600020905b81548152906001019060200180831162000abc57829003601f168201915b505050505084828151811062000af45762000af4620030a8565b6020026020010181905250601d6000898152602001908152602001600020805462000b1f9062003132565b80601f016020809104026020016040519081016040528092919081815260200182805462000b4d9062003132565b801562000b9e5780601f1062000b725761010080835404028352916020019162000b9e565b820191906000526020600020905b81548152906001019060200180831162000b8057829003601f168201915b505050505083828151811062000bb85762000bb8620030a8565b6020026020010181905250601e6000898152602001908152602001600020805462000be39062003132565b80601f016020809104026020016040519081016040528092919081815260200182805462000c119062003132565b801562000c625780601f1062000c365761010080835404028352916020019162000c62565b820191906000526020600020905b81548152906001019060200180831162000c4457829003601f168201915b505050505082828151811062000c7c5762000c7c620030a8565b602090810291909101810191909152600089815260048252604080822080547fffff0000000000000000000000000000000000000000000000000000000000001681556001810183905560020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600790925290812062000d029162002c0f565b6000888152601d6020526040812062000d1b9162002c0f565b6000888152601e6020526040812062000d349162002c0f565b600088815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562000d7560028962001df0565b5060c0870151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8d16602083015289917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062000de68162003187565b915050620006db565b5073ffffffffffffffffffffffffffffffffffffffff891660009081526021602052604090205462000e2390899062003106565b73ffffffffffffffffffffffffffffffffffffffff8a1660008181526021602052604090209190915562000e59908b8a62001ca5565b60008c8c868167ffffffffffffffff81111562000e7a5762000e7a62002df0565b60405190808252806020026020018201604052801562000ea4578160200160208202803683370190505b508988888860405160200162000ec2989796959493929190620033b9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282526016547faab9edd6000000000000000000000000000000000000000000000000000000008452915190935073ffffffffffffffffffffffffffffffffffffffff808f1693638e86139b939091169163c71249ab91600491869163aab9edd6918482019160209190819003860181865afa15801562000f72573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f98919062003498565b866040518463ffffffff1660e01b815260040162000fb993929190620034bd565b600060405180830381865afa15801562000fd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526200101f9190810190620034e4565b6040518263ffffffff1660e01b81526004016200103d91906200355b565b600060405180830381600087803b1580156200105857600080fd5b505af11580156200106d573d6000803e3d6000fd5b5050505050505050505050505050505050565b6002336000908152601c602052604090205460ff166003811115620010a957620010a962003079565b14158015620010df57506003336000908152601c602052604090205460ff166003811115620010dc57620010dc62003079565b14155b1562001117576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080808080806200112d888a018a62003882565b965096509650965096509650965060005b8751811015620013fc57600073ffffffffffffffffffffffffffffffffffffffff16878281518110620011755762001175620030a8565b60200260200101516080015173ffffffffffffffffffffffffffffffffffffffff16036200128957858181518110620011b257620011b2620030a8565b6020026020010151307f0000000000000000000000000000000000000000000000000000000000000000604051620011ea9062002c4e565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562001234573d6000803e3d6000fd5b508782815181106200124a576200124a620030a8565b60200260200101516080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b62001341888281518110620012a257620012a2620030a8565b6020026020010151888381518110620012bf57620012bf620030a8565b6020026020010151878481518110620012dc57620012dc620030a8565b6020026020010151878581518110620012f957620012f9620030a8565b6020026020010151878681518110620013165762001316620030a8565b6020026020010151878781518110620013335762001333620030a8565b602002602001015162001e07565b878181518110620013565762001356620030a8565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71888381518110620013945762001394620030a8565b602002602001015160c0015133604051620013df9291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620013f38162003187565b9150506200113e565b50505050505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200143c57506200143a60093362002324565b155b1562001474576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8a163b620014c3576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620014ce8762002354565b905060008a307f0000000000000000000000000000000000000000000000000000000000000000604051620015039062002c4e565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f0801580156200154d573d6000803e3d6000fd5b5090506200163e826040518061012001604052806000151581526020016000151581526020018d63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff168152508b89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062001e079050565b601680547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690601c6200167683620039b3565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128b8b604051620016ef92919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d87876040516200172b929190620039d9565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200176591906200355b565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850846040516200179f91906200355b565b60405180910390a2509998505050505050505050565b6000818152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915290620018d960005473ffffffffffffffffffffffffffffffffffffffff1690565b61010083015173ffffffffffffffffffffffffffffffffffffffff90811660009081526022602090815260408083206002015460155482517f57e871e70000000000000000000000000000000000000000000000000000000081529251968616331497506bffffffffffffffffffffffff90911695939416926357e871e7926004808401939192918290030181865afa1580156200197b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620019a1919062003a26565b9050836060015163ffffffff16600003620019e8576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606084015163ffffffff9081161462001a2d576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215801562001a60575060008581526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562001a98576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8262001aae5762001aab6032826200311c565b90505b6000858152600460205260409020805463ffffffff8084166601000000000000027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff9092169190911790915562001b0b90600290879062001df016565b506000826bffffffffffffffffffffffff168560a001516fffffffffffffffffffffffffffffffff16101562001b7e5760a085015162001b4c908462003a40565b90508460c001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16111562001b7e575060c08401515b808560c0015162001b90919062003a40565b600087815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010089015173ffffffffffffffffffffffffffffffffffffffff168352602190915290205462001c229183169062003106565b61010086015173ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604080822092909255905167ffffffffffffffff84169188917f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f7911819190a3505050505050565b62001c97620025f3565b62001ca28162002678565b50565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905262001d349084906200276f565b505050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16331462001d97576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff9081161462001ca2576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062001dfe838362002882565b90505b92915050565b601454760100000000000000000000000000000000000000000000900460ff161562001e5f576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60175483517c010000000000000000000000000000000000000000000000000000000090910463ffffffff16101562001ec4576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856040015163ffffffff16108062001f0a5750601654604086015163ffffffff780100000000000000000000000000000000000000000000000090920482169116115b1562001f42576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562001fad576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010085015173ffffffffffffffffffffffffffffffffffffffff9081166000908152602260205260409020546701000000000000009004166200201d576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846004600088815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060c08201518160010160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050836005600088815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260076000888152602001908152602001600020908162002262919062003aba565b5060c085015161010086015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040902054620022ad916bffffffffffffffffffffffff16906200311c565b61010086015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020908152604080832093909355888252601d905220620022f2838262003aba565b506000868152601e602052604090206200230d828262003aba565b506200231b6002876200298d565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151562001dfe565b601554604080517f57e871e70000000000000000000000000000000000000000000000000000000081529051600092839273ffffffffffffffffffffffffffffffffffffffff90911691839183916385df51fd9160019184916357e871e79160048083019260209291908290030181865afa158015620023d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023fe919062003a26565b6200240a919062003106565b6040518263ffffffff1660e01b81526004016200242991815260200190565b602060405180830381865afa15801562002447573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200246d919062003a26565b60165460408051602081019390935230908301527c0100000000000000000000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f8110156200258157838282815181106200253d576200253d620030a8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080620025788162003187565b9150506200251d565b5084600181111562002597576200259762003079565b60f81b81600f81518110620025b057620025b0620030a8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350620025ea8162003be1565b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462002676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401620002b3565b565b3373ffffffffffffffffffffffffffffffffffffffff821603620026f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620002b3565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000620027d3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166200299b9092919063ffffffff16565b80519091501562001d345780806020019051810190620027f4919062003c24565b62001d34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401620002b3565b600081815260018301602052604081205480156200297b576000620028a960018362003106565b8554909150600090620028bf9060019062003106565b90508181146200292b576000866000018281548110620028e357620028e3620030a8565b9060005260206000200154905080876000018481548110620029095762002909620030a8565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200293f576200293f62003c44565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062001e01565b600091505062001e01565b5092915050565b600062001dfe8383620029b4565b6060620029ac848460008562002a06565b949350505050565b6000818152600183016020526040812054620029fd5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562001e01565b50600062001e01565b60608247101562002a9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401620002b3565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405162002ac5919062003c73565b60006040518083038185875af1925050503d806000811462002b04576040519150601f19603f3d011682016040523d82523d6000602084013e62002b09565b606091505b509150915062002b1c8783838762002b27565b979650505050505050565b6060831562002bc257825160000362002bba5773ffffffffffffffffffffffffffffffffffffffff85163b62002bba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620002b3565b5081620029ac565b620029ac838381511562002bd95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620002b391906200355b565b50805462002c1d9062003132565b6000825580601f1062002c2e575050565b601f01602090049060005260206000209081019062001ca2919062002c5c565b6103ca8062003c9283390190565b5b8082111562002c73576000815560010162002c5d565b5090565b73ffffffffffffffffffffffffffffffffffffffff8116811462001ca257600080fd5b803562002ca78162002c77565b919050565b60008060006040848603121562002cc257600080fd5b833567ffffffffffffffff8082111562002cdb57600080fd5b818601915086601f83011262002cf057600080fd5b81358181111562002d0057600080fd5b8760208260051b850101111562002d1657600080fd5b6020928301955093505084013562002d2e8162002c77565b809150509250925092565b60008083601f84011262002d4c57600080fd5b50813567ffffffffffffffff81111562002d6557600080fd5b60208301915083602082850101111562002d7e57600080fd5b9250929050565b6000806020838503121562002d9957600080fd5b823567ffffffffffffffff81111562002db157600080fd5b62002dbf8582860162002d39565b90969095509350505050565b803563ffffffff8116811462002ca757600080fd5b80356002811062002ca757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171562002e465762002e4662002df0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171562002e965762002e9662002df0565b604052919050565b600067ffffffffffffffff82111562002ebb5762002ebb62002df0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011262002ef957600080fd5b813562002f1062002f0a8262002e9e565b62002e4c565b81815284602083860101111562002f2657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121562002f6357600080fd5b62002f6e8a62002c9a565b985062002f7e60208b0162002dcb565b975062002f8e60408b0162002c9a565b965062002f9e60608b0162002de0565b955062002fae60808b0162002c9a565b945060a08a013567ffffffffffffffff8082111562002fcc57600080fd5b62002fda8d838e0162002d39565b909650945060c08c013591508082111562002ff457600080fd5b620030028d838e0162002ee7565b935060e08c01359150808211156200301957600080fd5b50620030288c828d0162002ee7565b9150509295985092959850929598565b6000602082840312156200304b57600080fd5b5035919050565b6000602082840312156200306557600080fd5b8135620030728162002c77565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111562001e015762001e01620030d7565b8082018082111562001e015762001e01620030d7565b600181811c908216806200314757607f821691505b60208210810362003181577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203620031bb57620031bb620030d7565b5060010190565b600081518084526020808501945080840160005b838110156200329b5781518051151588528381015115158489015260408082015163ffffffff908116918a01919091526060808301518216908a015260808083015173ffffffffffffffffffffffffffffffffffffffff908116918b019190915260a0808401516fffffffffffffffffffffffffffffffff16908b015260c0808401516bffffffffffffffffffffffff16908b015260e080840151909216918a01919091526101009182015116908801526101209096019590820190600101620031d6565b509495945050505050565b600081518084526020808501945080840160005b838110156200329b57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101620032ba565b60005b838110156200330b578181015183820152602001620032f1565b50506000910152565b600081518084526200332e816020860160208601620032ee565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015620033ac5782840389526200339984835162003314565b988501989350908401906001016200337e565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a1115620033f657600080fd5b8960051b808c838601378301838103820160208501526200341a8282018b620031c2565b9150508281036040840152620034318189620032a6565b90508281036060840152620034478188620032a6565b905082810360808401526200345d818762003360565b905082810360a084015262003473818662003360565b905082810360c084015262003489818562003360565b9b9a5050505050505050505050565b600060208284031215620034ab57600080fd5b815160ff811681146200307257600080fd5b60ff8416815260ff83166020820152606060408201526000620025ea606083018462003314565b600060208284031215620034f757600080fd5b815167ffffffffffffffff8111156200350f57600080fd5b8201601f810184136200352157600080fd5b80516200353262002f0a8262002e9e565b8181528560208385010111156200354857600080fd5b620025ea826020830160208601620032ee565b60208152600062001dfe602083018462003314565b600067ffffffffffffffff8211156200358d576200358d62002df0565b5060051b60200190565b600082601f830112620035a957600080fd5b81356020620035bc62002f0a8362003570565b82815260059290921b84018101918181019086841115620035dc57600080fd5b8286015b84811015620035f95780358352918301918301620035e0565b509695505050505050565b801515811462001ca257600080fd5b803562002ca78162003604565b80356fffffffffffffffffffffffffffffffff8116811462002ca757600080fd5b80356bffffffffffffffffffffffff8116811462002ca757600080fd5b600082601f8301126200367057600080fd5b813560206200368362002f0a8362003570565b8281526101209283028501820192828201919087851115620036a457600080fd5b8387015b858110156200377e5781818a031215620036c25760008081fd5b620036cc62002e1f565b620036d78262003613565b8152620036e686830162003613565b868201526040620036f981840162002dcb565b9082015260606200370c83820162002dcb565b9082015260806200371f83820162002c9a565b9082015260a06200373283820162003620565b9082015260c06200374583820162003641565b9082015260e06200375883820162002dcb565b908201526101006200376c83820162002c9a565b908201528452928401928101620036a8565b5090979650505050505050565b600082601f8301126200379d57600080fd5b81356020620037b062002f0a8362003570565b82815260059290921b84018101918181019086841115620037d057600080fd5b8286015b84811015620035f9578035620037ea8162002c77565b8352918301918301620037d4565b600082601f8301126200380a57600080fd5b813560206200381d62002f0a8362003570565b82815260059290921b840181019181810190868411156200383d57600080fd5b8286015b84811015620035f957803567ffffffffffffffff811115620038635760008081fd5b620038738986838b010162002ee7565b84525091830191830162003841565b600080600080600080600060e0888a0312156200389e57600080fd5b873567ffffffffffffffff80821115620038b757600080fd5b620038c58b838c0162003597565b985060208a0135915080821115620038dc57600080fd5b620038ea8b838c016200365e565b975060408a01359150808211156200390157600080fd5b6200390f8b838c016200378b565b965060608a01359150808211156200392657600080fd5b620039348b838c016200378b565b955060808a01359150808211156200394b57600080fd5b620039598b838c01620037f8565b945060a08a01359150808211156200397057600080fd5b6200397e8b838c01620037f8565b935060c08a01359150808211156200399557600080fd5b50620039a48a828b01620037f8565b91505092959891949750929550565b600063ffffffff808316818103620039cf57620039cf620030d7565b6001019392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60006020828403121562003a3957600080fd5b5051919050565b6bffffffffffffffffffffffff828116828216039080821115620029865762002986620030d7565b601f82111562001d3457600081815260208120601f850160051c8101602086101562003a915750805b601f850160051c820191505b8181101562003ab25782815560010162003a9d565b505050505050565b815167ffffffffffffffff81111562003ad75762003ad762002df0565b62003aef8162003ae8845462003132565b8462003a68565b602080601f83116001811462003b45576000841562003b0e5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562003ab2565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101562003b945788860151825594840194600190910190840162003b73565b508582101562003bd157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8051602080830151919081101562003181577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b60006020828403121562003c3757600080fd5b8151620030728162003604565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825162003c87818460208701620032ee565b919091019291505056fe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000aa164736f6c6343000813000a", } @@ -5100,7 +5101,7 @@ func (AutomationRegistryLogicABillingConfigOverrideRemoved) Topic() common.Hash } func (AutomationRegistryLogicABillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") + return common.HexToHash("0xca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba3") } func (AutomationRegistryLogicACancelledUpkeepReport) Topic() common.Hash { diff --git a/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go index d26c12c1afd..04087c52e11 100644 --- a/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go @@ -34,6 +34,7 @@ type AutomationRegistryBase23BillingConfig struct { GasFeePPB uint32 FlatFeeMilliCents *big.Int PriceFeed common.Address + Decimals uint8 FallbackPrice *big.Int MinSpend *big.Int } @@ -44,8 +45,8 @@ type AutomationRegistryBase23BillingOverrides struct { } var AutomationRegistryLogicBMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicC2_3\",\"name\":\"logicC\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101806040523480156200001257600080fd5b5060405162005a3238038062005a3283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e051610100516101205161014051610160516152f86200073a60003960008181610182015261022f0152600081816120c5015261226b01526000612b910152600050506000612ec701526000613c3b01526000612fa1015260008181610c4701528181610d0801528181610dd30152612c5201526152f86000f3fe6080604052600436106101805760003560e01c80638765ecbe116100d6578063aed2e9291161007f578063ce7dc5b411610059578063ce7dc5b4146104b1578063f2fde38b146104d1578063f7d334ba146104f157610180565b8063aed2e9291461043a578063b148ab6b14610471578063cd7f71b51461049157610180565b8063948108f7116100b0578063948108f7146103e7578063a72aa27e146103fa578063a86e17811461041a57610180565b80638765ecbe1461037c5780638da5cb5b1461039c5780638dcf0fe7146103c757610180565b806354b7faae1161013857806371fae17f1161011257806371fae17f14610327578063744bfe611461034757806379ba50971461036757610180565b806354b7faae146102b457806368d369d8146102d457806371791aa0146102f457610180565b8063349e8cca11610169578063349e8cca146102205780634ee88d35146102745780635165f2f51461029457610180565b80631a2af011146101c757806329c5efad146101e7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156101c0573d6000f35b3d6000fd5b005b3480156101d357600080fd5b506101c56101e23660046142cc565b610511565b3480156101f357600080fd5b50610207610202366004614440565b610617565b604051610217949392919061455f565b60405180910390f35b34801561022c57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610217565b34801561028057600080fd5b506101c561028f3660046145e1565b6108f5565b3480156102a057600080fd5b506101c56102af36600461462d565b610957565b3480156102c057600080fd5b506101c56102cf366004614646565b610b09565b3480156102e057600080fd5b506101c56102ef366004614672565b610d7c565b34801561030057600080fd5b5061031461030f366004614440565b611008565b60405161021797969594939291906146b3565b34801561033357600080fd5b506101c561034236600461462d565b61176c565b34801561035357600080fd5b506101c56103623660046142cc565b611802565b34801561037357600080fd5b506101c5611c7a565b34801561038857600080fd5b506101c561039736600461462d565b611d77565b3480156103a857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661024f565b3480156103d357600080fd5b506101c56103e23660046145e1565b611f2c565b6101c56103f5366004614701565b611f81565b34801561040657600080fd5b506101c5610415366004614749565b612343565b34801561042657600080fd5b506101c561043536600461476e565b612442565b34801561044657600080fd5b5061045a6104553660046145e1565b612523565b604080519215158352602083019190915201610217565b34801561047d57600080fd5b506101c561048c36600461462d565b6126ce565b34801561049d57600080fd5b506101c56104ac3660046145e1565b6128fb565b3480156104bd57600080fd5b506102076104cc3660046147e8565b6129b2565b3480156104dd57600080fd5b506101c56104ec3660046148ca565b612a74565b3480156104fd57600080fd5b5061031461050c36600461462d565b612a88565b61051a82612ac4565b3373ffffffffffffffffffffffffffffffffffffffff821603610569576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146106135760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b60006060600080610626612b79565b600086815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff620100008204811695830195909552660100000000000081048516606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490941660e0820152600290910154909216908201525a9150600080826080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a091906148f7565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16896040516107e09190614914565b60006040518083038160008787f1925050503d806000811461081e576040519150601f19603f3d011682016040523d82523d6000602084013e610823565b606091505b50915091505a610833908561495f565b93508161085c5760006040518060200160405280600081525060079650965096505050506108ec565b8080602001905181019061087091906149c7565b90975095508661089c5760006040518060200160405280600081525060049650965096505050506108ec565b60185486517401000000000000000000000000000000000000000090910463ffffffff1610156108e85760006040518060200160405280600081525060059650965096505050506108ec565b5050505b92959194509250565b6108fe83612ac4565b6000838152601d60205260409020610917828483614aac565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405161094a929190614c10565b60405180910390a2505050565b61096081612ac4565b600081815260046020908152604091829020825161012081018452815460ff808216151580845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152610a9a576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610ad9600283612bea565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b610b11612bff565b73ffffffffffffffffffffffffffffffffffffffff8216610b5e576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b68612c50565b90506000811215610bb4576040517fcf47918100000000000000000000000000000000000000000000000000000000815260006004820152602481018390526044015b60405180910390fd5b80821115610bf8576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb69190614c24565b905080610cef576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051610d6e91815260200190565b60405180910390a350505050565b610d84612bff565b73ffffffffffffffffffffffffffffffffffffffff8216610dd1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e56576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e60612c50565b1215610e98576040517f981bb6a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f389190614c3f565b610f42919061495f565b905080821115610f88576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b610fa973ffffffffffffffffffffffffffffffffffffffff85168484612d1f565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051610d6e91815260200190565b60006060600080600080600061101c612b79565b60006110278a612df8565b905060006014604051806101200160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160139054906101000a900461ffff1661ffff1661ffff1681526020016000820160159054906101000a900460ff1660ff1660ff1681526020016000820160169054906101000a900460ff161515151581526020016000820160179054906101000a900460ff161515151581526020016000820160189054906101000a900460ff161515151581526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d8152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000808360a00151156113ea5750506040805160208101825260008082529290910151919a5098506009975089965063ffffffff169450859350839250611760915050565b606083015163ffffffff908116146114345750506040805160208101825260008082529290910151919a5098506001975089965063ffffffff169450859350839250611760915050565b8251156114735750506040805160208101825260008082529290910151919a5098506002975089965063ffffffff169450859350839250611760915050565b61147c84612ea3565b8094508198508299505050506114a18e858786604001518b8b888a6101000151613095565b9050806bffffffffffffffffffffffff168360c001516bffffffffffffffffffffffff1610156115035750506040805160208101825260008082529290910151919a5098506006975089965063ffffffff169450859350839250611760915050565b505060006115128d858e613405565b90505a9750600080836080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158d91906148f7565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16846040516115cd9190614914565b60006040518083038160008787f1925050503d806000811461160b576040519150601f19603f3d011682016040523d82523d6000602084013e611610565b606091505b50915091505a611620908b61495f565b9950816116a6576018548151780100000000000000000000000000000000000000000000000090910463ffffffff1610156116855750506040805160208101825260008082529390910151929b509950600898505063ffffffff169450611760915050565b604090930151929a50600399505063ffffffff909116955061176092505050565b808060200190518101906116ba91906149c7565b909d509b508c6116f45750506040805160208101825260008082529390910151929b509950600498505063ffffffff169450611760915050565b6018548c517401000000000000000000000000000000000000000090910463ffffffff16101561174e5750506040805160208101825260008082529390910151929b509950600598505063ffffffff169450611760915050565b5050506040015163ffffffff16945050505b92959891949750929550565b6117746135e5565b600081815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055602390915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690555182917f97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a91a250565b60145477010000000000000000000000000000000000000000000000900460ff161561185a576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff81166118e9576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615158387015263ffffffff620100008304811684870152660100000000000083048116606085015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009093048316608085015260018501546fffffffffffffffffffffffffffffffff811660a08601526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08601527c010000000000000000000000000000000000000000000000000000000090041660e084015260029093015481169282019290925286855260059093529220549091163314611a29576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554604080517f57e871e7000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916357e871e7916004808201926020929091908290030181865afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190614c3f565b816060015163ffffffff161115611b00576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526004602090815260408083206001015461010085015173ffffffffffffffffffffffffffffffffffffffff1684526021909252909120547001000000000000000000000000000000009091046bffffffffffffffffffffffff1690611b6b90829061495f565b6101008301805173ffffffffffffffffffffffffffffffffffffffff908116600090815260216020908152604080832095909555888252600490529290922060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16905551611bee9116846bffffffffffffffffffffffff8416612d1f565b604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611cfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610bab565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611d8081612ac4565b600081815260046020908152604091829020825161012081018452815460ff808216158015845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152611eba576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611efc600283613636565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b611f3583612ac4565b6000838152601e60205260409020611f4e828483614aac565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850838360405161094a929190614c10565b600082815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e084015260029093015416928101929092529091146120bd576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3415612159577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681610100015173ffffffffffffffffffffffffffffffffffffffff161461214d576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61215634613642565b91505b818160c001516121699190614c58565b600084815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010085015173ffffffffffffffffffffffffffffffffffffffff16835260219091529020546121f991841690614c7d565b61010082015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040812091909155349003612269576101008101516122649073ffffffffffffffffffffffffffffffffffffffff1633306bffffffffffffffffffffffff86166136e4565b6122f9565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836bffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122df57600080fd5b505af11580156122f3573d6000803e3d6000fd5b50505050505b6040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6108fc8163ffffffff161080612380575060165463ffffffff78010000000000000000000000000000000000000000000000009091048116908216115b156123b7576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123c082612ac4565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff166201000063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c91015b60405180910390a25050565b61244a6135e5565b6000828152600460205260409020546601000000000000900463ffffffff908116146124a2576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556023909152902081906124f08282614ca1565b905050817fd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340826040516124369190614d28565b60008061252e612b79565b601454760100000000000000000000000000000000000000000000900460ff1615612585576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615158386015262010000820463ffffffff90811684880181905266010000000000008404821660608601526a010000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff9081166080860181905260018701546fffffffffffffffffffffffffffffffff811660a088015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08801527c0100000000000000000000000000000000000000000000000000000000900490921660e0860152600290950154909416908301528451601f890185900485028101850190955287855290936126c193899089908190840183828082843760009201919091525061374892505050565b9097909650945050505050565b600081815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e0840152600290930154169281019290925290911461280a576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612867576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b61290483612ac4565b6017547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16811115612966576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260076020526040902061297f828483614aac565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d838360405161094a929190614c10565b600060606000806000634b56a42e60e01b8888886040516024016129d893929190614d5f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050612a618982610617565b929c919b50995090975095505050505050565b612a7c613963565b612a85816139e4565b50565b600060606000806000806000612aad8860405180602001604052806000815250611008565b959e949d50929b5090995097509550909350915050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b21576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff90811614612a85576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612be8576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000612bf68383613ad9565b90505b92915050565b60185473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015612cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d109190614c3f565b612d1a9190614df5565b905090565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612df39084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613b28565b505050565b6000818160045b600f811015612e85577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612e3d57612e3d614e15565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612e7357506000949350505050565b80612e7d81614e44565b915050612dff565b5081600f1a6001811115612e9b57612e9b6144f5565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f549190614e96565b5094509092505050600081131580612f6b57508142105b80612f8c5750828015612f8c5750612f83824261495f565b8463ffffffff16105b15612f9b576019549650612f9f565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561300a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302e9190614e96565b509450909250505060008113158061304557508142105b806130665750828015613066575061305d824261495f565b8463ffffffff16105b1561307557601a549550613079565b8095505b86866130848a613c34565b965096509650505050509193909250565b60008080808960018111156130ac576130ac6144f5565b036130bb575062016b48613110565b60018960018111156130cf576130cf6144f5565b036130de57506201ccf0613110565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a6080015160016131239190614ee6565b6131319060ff166040614eff565b60185461315f906103a49074010000000000000000000000000000000000000000900463ffffffff16614c7d565b6131699190614c7d565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156131da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131fe9190614f16565b90925090508183613210836018614c7d565b61321a9190614eff565b60808f015161322a906001614ee6565b6132399060ff166115e0614eff565b6132439190614c7d565b61324d9190614c7d565b6132579085614c7d565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156132ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ee9190614c3f565b8d6060015161ffff166133019190614eff565b945050505060006133128b86613d25565b60008d815260046020526040902054909150610100900460ff16156133775760008c81526023602090815260409182902082518084019093525463ffffffff811680845262ffffff640100000000909204821693830193845284529151909116908201525b60006133e18c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250613e76565b602081015181519192506133f491614c58565b9d9c50505050505050505050505050565b6060600083600181111561341b5761341b6144f5565b036134e4576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009161346091602401614fd5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506135de565b60018360018111156134f8576134f86144f5565b036130de57600082806020019051810190613513919061504e565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009161355891849160240161515e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506135de9050565b9392505050565b60175473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612bf68383614046565b60006bffffffffffffffffffffffff8211156136e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610bab565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526137429085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d71565b50505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156137a5576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061381a908590602401615229565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906138ed908790879060040161523c565b60408051808303816000875af115801561390b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392f9190615255565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610bab565b3373ffffffffffffffffffffffffffffffffffffffff821603613a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610bab565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054613b2057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612bf9565b506000612bf9565b6000613b8a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166141399092919063ffffffff16565b805190915015612df35780806020019051810190613ba89190614c24565b612df3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610bab565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc89190614e96565b50935050925050600082131580613cde57508042105b80613d0e57506000846040015162ffffff16118015613d0e5750613d02814261495f565b846040015162ffffff16105b15613d1e575050601b5492915050565b5092915050565b604080516060810182526000808252602080830182815283850183905273ffffffffffffffffffffffffffffffffffffffff868116845260229092528483208054640100000000810462ffffff1690925263ffffffff8216855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495909484936701000000000000009093049092169163feaf968c9160048082019260a0929091908290030181865afa158015613de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0b9190614e96565b50935050925050600082131580613e2157508042105b80613e5157506000866040015162ffffff16118015613e515750613e45814261495f565b866040015162ffffff16105b15613e655760018301546040850152613e6d565b604084018290525b50505092915050565b6040805160808101825260008082526020820181905291810182905260608101919091526000836060015161ffff168360600151613eb49190614eff565b90508261010001518015613ec75750803a105b15613ecf57503a5b60008360a00151846040015185602001518660000151613eef9190614c7d565b613ef99085614eff565b613f039190614c7d565b613f0d9190614eff565b9050613f2b8460e001516040015182613f269190615281565b613642565b6bffffffffffffffffffffffff1683526080840151613f4e90613f269083615281565b6bffffffffffffffffffffffff16604084015260e084015160200151600090613f859062ffffff16683635c9adc5dea00000614eff565b9050600081633b9aca008760a001518860e001516000015163ffffffff1689604001518a6000015189613fb89190614eff565b613fc29190614c7d565b613fcc9190614eff565b613fd69190614eff565b613fe09190615281565b613fea9190614c7d565b90506140038660e001516040015182613f269190615281565b6bffffffffffffffffffffffff166020860152608086015161402990613f269083615281565b6bffffffffffffffffffffffff1660608601525050505092915050565b6000818152600183016020526040812054801561412f57600061406a60018361495f565b855490915060009061407e9060019061495f565b90508181146140e357600086600001828154811061409e5761409e614e15565b90600052602060002001549050808760000184815481106140c1576140c1614e15565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806140f4576140f46152bc565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612bf9565b6000915050612bf9565b6060612e9b8484600085856000808673ffffffffffffffffffffffffffffffffffffffff16858760405161416d9190614914565b60006040518083038185875af1925050503d80600081146141aa576040519150601f19603f3d011682016040523d82523d6000602084013e6141af565b606091505b50915091506141c0878383876141cb565b979650505050505050565b6060831561426157825160000361425a5773ffffffffffffffffffffffffffffffffffffffff85163b61425a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bab565b5081612e9b565b612e9b83838151156142765781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bab9190615229565b73ffffffffffffffffffffffffffffffffffffffff81168114612a8557600080fd5b600080604083850312156142df57600080fd5b8235915060208301356142f1816142aa565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff8111828210171561434f5761434f6142fc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561439c5761439c6142fc565b604052919050565b600067ffffffffffffffff8211156143be576143be6142fc565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126143fb57600080fd5b813561440e614409826143a4565b614355565b81815284602083860101111561442357600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561445357600080fd5b82359150602083013567ffffffffffffffff81111561447157600080fd5b61447d858286016143ea565b9150509250929050565b60005b838110156144a257818101518382015260200161448a565b50506000910152565b600081518084526144c3816020860160208601614487565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811061455b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600061457a60808301866144ab565b90506145896040830185614524565b82606083015295945050505050565b60008083601f8401126145aa57600080fd5b50813567ffffffffffffffff8111156145c257600080fd5b6020830191508360208285010111156145da57600080fd5b9250929050565b6000806000604084860312156145f657600080fd5b83359250602084013567ffffffffffffffff81111561461457600080fd5b61462086828701614598565b9497909650939450505050565b60006020828403121561463f57600080fd5b5035919050565b6000806040838503121561465957600080fd5b8235614664816142aa565b946020939093013593505050565b60008060006060848603121561468757600080fd5b8335614692816142aa565b925060208401356146a2816142aa565b929592945050506040919091013590565b871515815260e0602082015260006146ce60e08301896144ab565b90506146dd6040830188614524565b8560608301528460808301528360a08301528260c083015298975050505050505050565b6000806040838503121561471457600080fd5b8235915060208301356bffffffffffffffffffffffff811681146142f157600080fd5b63ffffffff81168114612a8557600080fd5b6000806040838503121561475c57600080fd5b8235915060208301356142f181614737565b600080828403606081121561478257600080fd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820112156147b657600080fd5b506020830190509250929050565b600067ffffffffffffffff8211156147de576147de6142fc565b5060051b60200190565b600080600080606085870312156147fe57600080fd5b8435935060208086013567ffffffffffffffff8082111561481e57600080fd5b818801915088601f83011261483257600080fd5b8135614840614409826147c4565b81815260059190911b8301840190848101908b83111561485f57600080fd5b8585015b838110156148975780358581111561487b5760008081fd5b6148898e89838a01016143ea565b845250918601918601614863565b509750505060408801359250808311156148b057600080fd5b50506148be87828801614598565b95989497509550505050565b6000602082840312156148dc57600080fd5b81356135de816142aa565b80516148f2816142aa565b919050565b60006020828403121561490957600080fd5b81516135de816142aa565b60008251614926818460208701614487565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115612bf957612bf9614930565b805180151581146148f257600080fd5b600082601f83011261499357600080fd5b81516149a1614409826143a4565b8181528460208386010111156149b657600080fd5b612e9b826020830160208701614487565b600080604083850312156149da57600080fd5b6149e383614972565b9150602083015167ffffffffffffffff8111156149ff57600080fd5b61447d85828601614982565b600181811c90821680614a1f57607f821691505b602082108103614a58577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612df357600081815260208120601f850160051c81016020861015614a855750805b601f850160051c820191505b81811015614aa457828155600101614a91565b505050505050565b67ffffffffffffffff831115614ac457614ac46142fc565b614ad883614ad28354614a0b565b83614a5e565b6000601f841160018114614b2a5760008515614af45750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614bc0565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614b795786850135825560209485019460019092019101614b59565b5086821015614bb4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612e9b602083018486614bc7565b600060208284031215614c3657600080fd5b612bf682614972565b600060208284031215614c5157600080fd5b5051919050565b6bffffffffffffffffffffffff818116838216019080821115613d1e57613d1e614930565b80820180821115612bf957612bf9614930565b62ffffff81168114612a8557600080fd5b8135614cac81614737565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082161783556020840135614cec81614c90565b66ffffff000000008160201b16837fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008416171784555050505050565b604081018235614d3781614737565b63ffffffff1682526020830135614d4d81614c90565b62ffffff811660208401525092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b83811015614dd4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552614dc28683516144ab565b95509382019390820190600101614d88565b505085840381870152505050614deb818587614bc7565b9695505050505050565b8181036000831280158383131683831282161715613d1e57613d1e614930565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614e7557614e75614930565b5060010190565b805169ffffffffffffffffffff811681146148f257600080fd5b600080600080600060a08688031215614eae57600080fd5b614eb786614e7c565b9450602086015193506040860151925060608601519150614eda60808701614e7c565b90509295509295909350565b60ff8181168382160190811115612bf957612bf9614930565b8082028115828204841417612bf957612bf9614930565b60008060408385031215614f2957600080fd5b505080516020909101519092909150565b60008154614f4781614a0b565b808552602060018381168015614f645760018114614f9c57614fca565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550614fca565b866000528260002060005b85811015614fc25781548a8201860152908301908401614fa7565b890184019650505b505050505092915050565b602081526000612bf66020830184614f3a565b600082601f830112614ff957600080fd5b81516020615009614409836147c4565b82815260059290921b8401810191818101908684111561502857600080fd5b8286015b84811015615043578051835291830191830161502c565b509695505050505050565b60006020828403121561506057600080fd5b815167ffffffffffffffff8082111561507857600080fd5b90830190610100828603121561508d57600080fd5b61509561432b565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526150cd60a084016148e7565b60a082015260c0830151828111156150e457600080fd5b6150f087828601614fe8565b60c08301525060e08301518281111561510857600080fd5b61511487828601614982565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101561515357815187529582019590820190600101615137565b509495945050505050565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c08401516101008081850152506151cf610140840182615123565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030161012085015261520b82826144ab565b91505082810360208401526152208185614f3a565b95945050505050565b602081526000612bf660208301846144ab565b828152604060208201526000612e9b60408301846144ab565b6000806040838503121561526857600080fd5b61527183614972565b9150602083015190509250929050565b6000826152b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicC2_3\",\"name\":\"logicC\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20Metadata\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101806040523480156200001257600080fd5b5060405162005c0e38038062005c0e83398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e051610100516101205161014051610160516154d46200073a60003960008181610182015261022f0152600081816120c5015261226b01526000612b910152600050506000612ec701526000613c3b01526000612fa1015260008181610c4701528181610d0801528181610dd30152612c5201526154d46000f3fe6080604052600436106101805760003560e01c80638765ecbe116100d6578063aed2e9291161007f578063ce7dc5b411610059578063ce7dc5b4146104b1578063f2fde38b146104d1578063f7d334ba146104f157610180565b8063aed2e9291461043a578063b148ab6b14610471578063cd7f71b51461049157610180565b8063948108f7116100b0578063948108f7146103e7578063a72aa27e146103fa578063a86e17811461041a57610180565b80638765ecbe1461037c5780638da5cb5b1461039c5780638dcf0fe7146103c757610180565b806354b7faae1161013857806371fae17f1161011257806371fae17f14610327578063744bfe611461034757806379ba50971461036757610180565b806354b7faae146102b457806368d369d8146102d457806371791aa0146102f457610180565b8063349e8cca11610169578063349e8cca146102205780634ee88d35146102745780635165f2f51461029457610180565b80631a2af011146101c757806329c5efad146101e7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156101c0573d6000f35b3d6000fd5b005b3480156101d357600080fd5b506101c56101e236600461437c565b610511565b3480156101f357600080fd5b506102076102023660046144f0565b610617565b604051610217949392919061460f565b60405180910390f35b34801561022c57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610217565b34801561028057600080fd5b506101c561028f366004614691565b6108f5565b3480156102a057600080fd5b506101c56102af3660046146dd565b610957565b3480156102c057600080fd5b506101c56102cf3660046146f6565b610b09565b3480156102e057600080fd5b506101c56102ef366004614722565b610d7c565b34801561030057600080fd5b5061031461030f3660046144f0565b611008565b6040516102179796959493929190614763565b34801561033357600080fd5b506101c56103423660046146dd565b61176c565b34801561035357600080fd5b506101c561036236600461437c565b611802565b34801561037357600080fd5b506101c5611c7a565b34801561038857600080fd5b506101c56103973660046146dd565b611d77565b3480156103a857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661024f565b3480156103d357600080fd5b506101c56103e2366004614691565b611f2c565b6101c56103f53660046147b1565b611f81565b34801561040657600080fd5b506101c56104153660046147f9565b612343565b34801561042657600080fd5b506101c561043536600461481e565b612442565b34801561044657600080fd5b5061045a610455366004614691565b612523565b604080519215158352602083019190915201610217565b34801561047d57600080fd5b506101c561048c3660046146dd565b6126ce565b34801561049d57600080fd5b506101c56104ac366004614691565b6128fb565b3480156104bd57600080fd5b506102076104cc366004614898565b6129b2565b3480156104dd57600080fd5b506101c56104ec36600461497a565b612a74565b3480156104fd57600080fd5b5061031461050c3660046146dd565b612a88565b61051a82612ac4565b3373ffffffffffffffffffffffffffffffffffffffff821603610569576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146106135760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b60006060600080610626612b79565b600086815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff620100008204811695830195909552660100000000000081048516606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490941660e0820152600290910154909216908201525a9150600080826080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a091906149a7565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16896040516107e091906149c4565b60006040518083038160008787f1925050503d806000811461081e576040519150601f19603f3d011682016040523d82523d6000602084013e610823565b606091505b50915091505a6108339085614a0f565b93508161085c5760006040518060200160405280600081525060079650965096505050506108ec565b808060200190518101906108709190614a77565b90975095508661089c5760006040518060200160405280600081525060049650965096505050506108ec565b60185486517401000000000000000000000000000000000000000090910463ffffffff1610156108e85760006040518060200160405280600081525060059650965096505050506108ec565b5050505b92959194509250565b6108fe83612ac4565b6000838152601d60205260409020610917828483614b5c565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405161094a929190614cc0565b60405180910390a2505050565b61096081612ac4565b600081815260046020908152604091829020825161012081018452815460ff808216151580845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152610a9a576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610ad9600283612bea565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b610b11612bff565b73ffffffffffffffffffffffffffffffffffffffff8216610b5e576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b68612c50565b90506000811215610bb4576040517fcf47918100000000000000000000000000000000000000000000000000000000815260006004820152602481018390526044015b60405180910390fd5b80821115610bf8576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb69190614cd4565b905080610cef576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051610d6e91815260200190565b60405180910390a350505050565b610d84612bff565b73ffffffffffffffffffffffffffffffffffffffff8216610dd1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e56576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e60612c50565b1215610e98576040517f981bb6a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f389190614cef565b610f429190614a0f565b905080821115610f88576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b610fa973ffffffffffffffffffffffffffffffffffffffff85168484612d1f565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051610d6e91815260200190565b60006060600080600080600061101c612b79565b60006110278a612df8565b905060006014604051806101200160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160139054906101000a900461ffff1661ffff1661ffff1681526020016000820160159054906101000a900460ff1660ff1660ff1681526020016000820160169054906101000a900460ff161515151581526020016000820160179054906101000a900460ff161515151581526020016000820160189054906101000a900460ff161515151581526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d8152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000808360a00151156113ea5750506040805160208101825260008082529290910151919a5098506009975089965063ffffffff169450859350839250611760915050565b606083015163ffffffff908116146114345750506040805160208101825260008082529290910151919a5098506001975089965063ffffffff169450859350839250611760915050565b8251156114735750506040805160208101825260008082529290910151919a5098506002975089965063ffffffff169450859350839250611760915050565b61147c84612ea3565b8094508198508299505050506114a18e858786604001518b8b888a6101000151613095565b9050806bffffffffffffffffffffffff168360c001516bffffffffffffffffffffffff1610156115035750506040805160208101825260008082529290910151919a5098506006975089965063ffffffff169450859350839250611760915050565b505060006115128d858e613405565b90505a9750600080836080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158d91906149a7565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16846040516115cd91906149c4565b60006040518083038160008787f1925050503d806000811461160b576040519150601f19603f3d011682016040523d82523d6000602084013e611610565b606091505b50915091505a611620908b614a0f565b9950816116a6576018548151780100000000000000000000000000000000000000000000000090910463ffffffff1610156116855750506040805160208101825260008082529390910151929b509950600898505063ffffffff169450611760915050565b604090930151929a50600399505063ffffffff909116955061176092505050565b808060200190518101906116ba9190614a77565b909d509b508c6116f45750506040805160208101825260008082529390910151929b509950600498505063ffffffff169450611760915050565b6018548c517401000000000000000000000000000000000000000090910463ffffffff16101561174e5750506040805160208101825260008082529390910151929b509950600598505063ffffffff169450611760915050565b5050506040015163ffffffff16945050505b92959891949750929550565b6117746135e5565b600081815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055602390915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690555182917f97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a91a250565b60145477010000000000000000000000000000000000000000000000900460ff161561185a576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff81166118e9576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615158387015263ffffffff620100008304811684870152660100000000000083048116606085015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009093048316608085015260018501546fffffffffffffffffffffffffffffffff811660a08601526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08601527c010000000000000000000000000000000000000000000000000000000090041660e084015260029093015481169282019290925286855260059093529220549091163314611a29576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554604080517f57e871e7000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916357e871e7916004808201926020929091908290030181865afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190614cef565b816060015163ffffffff161115611b00576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526004602090815260408083206001015461010085015173ffffffffffffffffffffffffffffffffffffffff1684526021909252909120547001000000000000000000000000000000009091046bffffffffffffffffffffffff1690611b6b908290614a0f565b6101008301805173ffffffffffffffffffffffffffffffffffffffff908116600090815260216020908152604080832095909555888252600490529290922060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16905551611bee9116846bffffffffffffffffffffffff8416612d1f565b604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611cfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610bab565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611d8081612ac4565b600081815260046020908152604091829020825161012081018452815460ff808216158015845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152611eba576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611efc600283613636565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b611f3583612ac4565b6000838152601e60205260409020611f4e828483614b5c565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850838360405161094a929190614cc0565b600082815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e084015260029093015416928101929092529091146120bd576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3415612159577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681610100015173ffffffffffffffffffffffffffffffffffffffff161461214d576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61215634613642565b91505b818160c001516121699190614d08565b600084815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010085015173ffffffffffffffffffffffffffffffffffffffff16835260219091529020546121f991841690614d2d565b61010082015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040812091909155349003612269576101008101516122649073ffffffffffffffffffffffffffffffffffffffff1633306bffffffffffffffffffffffff86166136e4565b6122f9565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836bffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122df57600080fd5b505af11580156122f3573d6000803e3d6000fd5b50505050505b6040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6108fc8163ffffffff161080612380575060165463ffffffff78010000000000000000000000000000000000000000000000009091048116908216115b156123b7576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123c082612ac4565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff166201000063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c91015b60405180910390a25050565b61244a6135e5565b6000828152600460205260409020546601000000000000900463ffffffff908116146124a2576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556023909152902081906124f08282614d51565b905050817fd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340826040516124369190614dd8565b60008061252e612b79565b601454760100000000000000000000000000000000000000000000900460ff1615612585576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615158386015262010000820463ffffffff90811684880181905266010000000000008404821660608601526a010000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff9081166080860181905260018701546fffffffffffffffffffffffffffffffff811660a088015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08801527c0100000000000000000000000000000000000000000000000000000000900490921660e0860152600290950154909416908301528451601f890185900485028101850190955287855290936126c193899089908190840183828082843760009201919091525061374892505050565b9097909650945050505050565b600081815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e0840152600290930154169281019290925290911461280a576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612867576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b61290483612ac4565b6017547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16811115612966576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260076020526040902061297f828483614b5c565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d838360405161094a929190614cc0565b600060606000806000634b56a42e60e01b8888886040516024016129d893929190614e0f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050612a618982610617565b929c919b50995090975095505050505050565b612a7c613963565b612a85816139e4565b50565b600060606000806000806000612aad8860405180602001604052806000815250611008565b959e949d50929b5090995097509550909350915050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b21576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff90811614612a85576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612be8576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000612bf68383613ad9565b90505b92915050565b60185473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015612cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d109190614cef565b612d1a9190614ea5565b905090565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612df39084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613b28565b505050565b6000818160045b600f811015612e85577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612e3d57612e3d614ec5565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612e7357506000949350505050565b80612e7d81614ef4565b915050612dff565b5081600f1a6001811115612e9b57612e9b6145a5565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f549190614f46565b5094509092505050600081131580612f6b57508142105b80612f8c5750828015612f8c5750612f838242614a0f565b8463ffffffff16105b15612f9b576019549650612f9f565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561300a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302e9190614f46565b509450909250505060008113158061304557508142105b806130665750828015613066575061305d8242614a0f565b8463ffffffff16105b1561307557601a549550613079565b8095505b86866130848a613c34565b965096509650505050509193909250565b60008080808960018111156130ac576130ac6145a5565b036130bb575062016b48613110565b60018960018111156130cf576130cf6145a5565b036130de57506201ccf0613110565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a6080015160016131239190614f96565b6131319060ff166040614faf565b60185461315f906103a49074010000000000000000000000000000000000000000900463ffffffff16614d2d565b6131699190614d2d565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156131da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131fe9190614fc6565b90925090508183613210836018614d2d565b61321a9190614faf565b60808f015161322a906001614f96565b6132399060ff166115e0614faf565b6132439190614d2d565b61324d9190614d2d565b6132579085614d2d565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156132ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ee9190614cef565b8d6060015161ffff166133019190614faf565b945050505060006133128b86613d25565b60008d815260046020526040902054909150610100900460ff16156133775760008c81526023602090815260409182902082518084018452905463ffffffff811680835264010000000090910462ffffff908116928401928352928501525116908201525b60006133e18c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250613ea1565b602081015181519192506133f491614d08565b9d9c50505050505050505050505050565b6060600083600181111561341b5761341b6145a5565b036134e4576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009161346091602401615085565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506135de565b60018360018111156134f8576134f86145a5565b036130de5760008280602001905181019061351391906150fe565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009161355891849160240161520e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506135de9050565b9392505050565b60175473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612bf683836140f6565b60006bffffffffffffffffffffffff8211156136e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610bab565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526137429085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d71565b50505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156137a5576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061381a9085906024016152d9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906138ed90879087906004016152ec565b60408051808303816000875af115801561390b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392f9190615305565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612be8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610bab565b3373ffffffffffffffffffffffffffffffffffffffff821603613a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610bab565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054613b2057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612bf9565b506000612bf9565b6000613b8a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166141e99092919063ffffffff16565b805190915015612df35780806020019051810190613ba89190614cd4565b612df3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610bab565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc89190614f46565b50935050925050600082131580613cde57508042105b80613d0e57506000846040015162ffffff16118015613d0e5750613d028142614a0f565b846040015162ffffff16105b15613d1e575050601b5492915050565b5092915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015613e12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e369190614f46565b50935050925050600082131580613e4c57508042105b80613e7c57506000866040015162ffffff16118015613e7c5750613e708142614a0f565b866040015162ffffff16105b15613e905760018301546060850152613e98565b606084018290525b50505092915050565b60408051608081018252600080825260208201819052918101829052606081019190915260008260e001516000015160ff1690506000846060015161ffff168460600151613eef9190614faf565b90508361010001518015613f025750803a105b15613f0a57503a5b600060128311613f1b576001613f31565b613f26601284614a0f565b613f3190600a615451565b9050600060128410613f44576001613f5a565b613f4f846012614a0f565b613f5a90600a615451565b905060008660a00151876040015188602001518960000151613f7c9190614d2d565b613f869087614faf565b613f909190614d2d565b613f9a9190614faf565b9050613fcc828860e0015160600151613fb39190614faf565b613fbd8584614faf565b613fc7919061545d565b613642565b6bffffffffffffffffffffffff1686526080870151613fef90613fc7908361545d565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906140289062ffffff16683635c9adc5dea00000614faf565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61405b9190614faf565b6140659190614d2d565b61406f9190614faf565b6140799190614faf565b614083919061545d565b61408d9190614d2d565b90506140b0848a60e00151606001516140a69190614faf565b613fbd8784614faf565b6bffffffffffffffffffffffff16602089015260808901516140d690613fc7908361545d565b6bffffffffffffffffffffffff1660608901525050505050505092915050565b600081815260018301602052604081205480156141df57600061411a600183614a0f565b855490915060009061412e90600190614a0f565b905081811461419357600086600001828154811061414e5761414e614ec5565b906000526020600020015490508087600001848154811061417157614171614ec5565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806141a4576141a4615498565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612bf9565b6000915050612bf9565b6060612e9b8484600085856000808673ffffffffffffffffffffffffffffffffffffffff16858760405161421d91906149c4565b60006040518083038185875af1925050503d806000811461425a576040519150601f19603f3d011682016040523d82523d6000602084013e61425f565b606091505b50915091506142708783838761427b565b979650505050505050565b6060831561431157825160000361430a5773ffffffffffffffffffffffffffffffffffffffff85163b61430a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bab565b5081612e9b565b612e9b83838151156143265781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bab91906152d9565b73ffffffffffffffffffffffffffffffffffffffff81168114612a8557600080fd5b6000806040838503121561438f57600080fd5b8235915060208301356143a18161435a565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff811182821017156143ff576143ff6143ac565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561444c5761444c6143ac565b604052919050565b600067ffffffffffffffff82111561446e5761446e6143ac565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126144ab57600080fd5b81356144be6144b982614454565b614405565b8181528460208386010111156144d357600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561450357600080fd5b82359150602083013567ffffffffffffffff81111561452157600080fd5b61452d8582860161449a565b9150509250929050565b60005b8381101561455257818101518382015260200161453a565b50506000910152565b60008151808452614573816020860160208601614537565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811061460b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600061462a608083018661455b565b905061463960408301856145d4565b82606083015295945050505050565b60008083601f84011261465a57600080fd5b50813567ffffffffffffffff81111561467257600080fd5b60208301915083602082850101111561468a57600080fd5b9250929050565b6000806000604084860312156146a657600080fd5b83359250602084013567ffffffffffffffff8111156146c457600080fd5b6146d086828701614648565b9497909650939450505050565b6000602082840312156146ef57600080fd5b5035919050565b6000806040838503121561470957600080fd5b82356147148161435a565b946020939093013593505050565b60008060006060848603121561473757600080fd5b83356147428161435a565b925060208401356147528161435a565b929592945050506040919091013590565b871515815260e06020820152600061477e60e083018961455b565b905061478d60408301886145d4565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080604083850312156147c457600080fd5b8235915060208301356bffffffffffffffffffffffff811681146143a157600080fd5b63ffffffff81168114612a8557600080fd5b6000806040838503121561480c57600080fd5b8235915060208301356143a1816147e7565b600080828403606081121561483257600080fd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561486657600080fd5b506020830190509250929050565b600067ffffffffffffffff82111561488e5761488e6143ac565b5060051b60200190565b600080600080606085870312156148ae57600080fd5b8435935060208086013567ffffffffffffffff808211156148ce57600080fd5b818801915088601f8301126148e257600080fd5b81356148f06144b982614874565b81815260059190911b8301840190848101908b83111561490f57600080fd5b8585015b838110156149475780358581111561492b5760008081fd5b6149398e89838a010161449a565b845250918601918601614913565b5097505050604088013592508083111561496057600080fd5b505061496e87828801614648565b95989497509550505050565b60006020828403121561498c57600080fd5b81356135de8161435a565b80516149a28161435a565b919050565b6000602082840312156149b957600080fd5b81516135de8161435a565b600082516149d6818460208701614537565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115612bf957612bf96149e0565b805180151581146149a257600080fd5b600082601f830112614a4357600080fd5b8151614a516144b982614454565b818152846020838601011115614a6657600080fd5b612e9b826020830160208701614537565b60008060408385031215614a8a57600080fd5b614a9383614a22565b9150602083015167ffffffffffffffff811115614aaf57600080fd5b61452d85828601614a32565b600181811c90821680614acf57607f821691505b602082108103614b08577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612df357600081815260208120601f850160051c81016020861015614b355750805b601f850160051c820191505b81811015614b5457828155600101614b41565b505050505050565b67ffffffffffffffff831115614b7457614b746143ac565b614b8883614b828354614abb565b83614b0e565b6000601f841160018114614bda5760008515614ba45750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614c70565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614c295786850135825560209485019460019092019101614c09565b5086821015614c64577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612e9b602083018486614c77565b600060208284031215614ce657600080fd5b612bf682614a22565b600060208284031215614d0157600080fd5b5051919050565b6bffffffffffffffffffffffff818116838216019080821115613d1e57613d1e6149e0565b80820180821115612bf957612bf96149e0565b62ffffff81168114612a8557600080fd5b8135614d5c816147e7565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082161783556020840135614d9c81614d40565b66ffffff000000008160201b16837fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008416171784555050505050565b604081018235614de7816147e7565b63ffffffff1682526020830135614dfd81614d40565b62ffffff811660208401525092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b83811015614e84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552614e7286835161455b565b95509382019390820190600101614e38565b505085840381870152505050614e9b818587614c77565b9695505050505050565b8181036000831280158383131683831282161715613d1e57613d1e6149e0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614f2557614f256149e0565b5060010190565b805169ffffffffffffffffffff811681146149a257600080fd5b600080600080600060a08688031215614f5e57600080fd5b614f6786614f2c565b9450602086015193506040860151925060608601519150614f8a60808701614f2c565b90509295509295909350565b60ff8181168382160190811115612bf957612bf96149e0565b8082028115828204841417612bf957612bf96149e0565b60008060408385031215614fd957600080fd5b505080516020909101519092909150565b60008154614ff781614abb565b808552602060018381168015615014576001811461504c5761507a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061507a565b866000528260002060005b858110156150725781548a8201860152908301908401615057565b890184019650505b505050505092915050565b602081526000612bf66020830184614fea565b600082601f8301126150a957600080fd5b815160206150b96144b983614874565b82815260059290921b840181019181810190868411156150d857600080fd5b8286015b848110156150f357805183529183019183016150dc565b509695505050505050565b60006020828403121561511057600080fd5b815167ffffffffffffffff8082111561512857600080fd5b90830190610100828603121561513d57600080fd5b6151456143db565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015261517d60a08401614997565b60a082015260c08301518281111561519457600080fd5b6151a087828601615098565b60c08301525060e0830151828111156151b857600080fd5b6151c487828601614a32565b60e08301525095945050505050565b600081518084526020808501945080840160005b83811015615203578151875295820195908201906001016151e7565b509495945050505050565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c084015161010080818501525061527f6101408401826151d3565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526152bb828261455b565b91505082810360208401526152d08185614fea565b95945050505050565b602081526000612bf6602083018461455b565b828152604060208201526000612e9b604083018461455b565b6000806040838503121561531857600080fd5b61532183614a22565b9150602083015190509250929050565b600181815b8085111561538a57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615370576153706149e0565b8085161561537d57918102915b93841c9390800290615336565b509250929050565b6000826153a157506001612bf9565b816153ae57506000612bf9565b81600181146153c457600281146153ce576153ea565b6001915050612bf9565b60ff8411156153df576153df6149e0565b50506001821b612bf9565b5060208310610133831016604e8410600b841016171561540d575081810a612bf9565b6154178383615331565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615449576154496149e0565b029392505050565b6000612bf68383615392565b600082615493577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a", } var AutomationRegistryLogicBABI = AutomationRegistryLogicBMetaData.ABI @@ -5280,7 +5281,7 @@ func (AutomationRegistryLogicBBillingConfigOverrideRemoved) Topic() common.Hash } func (AutomationRegistryLogicBBillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") + return common.HexToHash("0xca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba3") } func (AutomationRegistryLogicBCancelledUpkeepReport) Topic() common.Hash { diff --git a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go index eeec869db65..d648604895b 100644 --- a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go @@ -34,6 +34,7 @@ type AutomationRegistryBase23BillingConfig struct { GasFeePPB uint32 FlatFeeMilliCents *big.Int PriceFeed common.Address + Decimals uint8 FallbackPrice *big.Int MinSpend *big.Int } @@ -63,8 +64,8 @@ type AutomationRegistryBase23OnchainConfig struct { } var AutomationRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicA2_3\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6101806040523480156200001257600080fd5b50604051620061f0380380620061f083398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615abc620007346000396000818160be015261017101526000505060005050600050506000505060006137cc01526000505060008181610db101528181610ebf01528181610fea01528181611034015281816115820152612ef70152615abc6000f3fe6080604052600436106100bc5760003560e01c80638da5cb5b11610074578063b1dc65a41161004e578063b1dc65a4146102f6578063e3d0e71214610316578063f2fde38b14610336576100bc565b80638da5cb5b14610265578063a4c0ed3614610290578063afcb95d7146102b0576100bc565b806379ba5097116100a557806379ba5097146101b65780637bee169d146101cb57806381ff7048146101eb576100bc565b8063181f5a7714610103578063349e8cca14610162575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100fc573d6000f35b3d6000fd5b005b34801561010f57600080fd5b5061014c6040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b6040516101599190614513565b60405180910390f35b34801561016e57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610159565b3480156101c257600080fd5b50610101610356565b3480156101d757600080fd5b506101016101e6366004614a88565b610458565b3480156101f757600080fd5b5061024260175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610159565b34801561027157600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610191565b34801561029c57600080fd5b506101016102ab366004614be9565b610d99565b3480156102bc57600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff1690820152606001610159565b34801561030257600080fd5b50610101610311366004614c8a565b6110b5565b34801561032257600080fd5b50610101610331366004614d41565b611396565b34801561034257600080fd5b50610101610351366004614e0e565b6113d0565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104606113e4565b601f8851111561049c576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036104d9576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806104f857506104f0866003614e61565b60ff16885111155b1561052f576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461056a576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105748282611467565b61057e88886118cf565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050604051806101600160405280866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866000015163ffffffff168152602001866020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200186610100015173ffffffffffffffffffffffffffffffffffffffff168152602001601660010160149054906101000a900463ffffffff1663ffffffff168152602001601660010160189054906101000a900463ffffffff1663ffffffff168152602001866040015163ffffffff16815260200186610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018660c0015163ffffffff1681526020018660e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050846101600151601981905550846101800151601a81905550846101a00151601b819055506000601660010160189054906101000a900463ffffffff169050856101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba89190614e7d565b601780547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601491610c1f91859174010000000000000000000000000000000000000000900416614e96565b92506101000a81548163ffffffff021916908363ffffffff160217905550600086604051602001610c509190614f04565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610cb5904690309074010000000000000000000000000000000000000000900463ffffffff168d8d8d878d8d611f90565b601355600960008181610cc882826143fa565b5050505060005b876101c0015151811015610d2257610d0f886101c001518281518110610cf757610cf761508a565b6020026020010151600961203a90919063ffffffff16565b5080610d1a816150b9565b915050610ccf565b506013546017546040517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0592610d859286927401000000000000000000000000000000000000000090910463ffffffff16908f908f908f9089908f908f906150f1565b60405180910390a150505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610e08576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610e42576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e5082840184615187565b6000818152600460205260409020549091506601000000000000900463ffffffff90811614610eab576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600201547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614610f2f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260046020526040902060010154610f6e90859070010000000000000000000000000000000090046bffffffffffffffffffffffff166151a0565b600082815260046020908152604080832060010180546bffffffffffffffffffffffff95909516700100000000000000000000000000000000027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff9095169490941790935573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016825260219052205461101d9085906151c5565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660009081526021602090815260409182902093909355516bffffffffffffffffffffffff871681529087169183917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203910160405180910390a35050505050565b60005a60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff16610100820152919250611219576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16611262576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548a351461129e576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101516112ae9060016151d8565b60ff16861415806112bf5750858414155b156112f6576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113068a8a8a8a8a8a8a8a612065565b60006113128a8a6122ce565b905060208b0135600881901c63ffffffff1661132f848487612387565b836020015163ffffffff168163ffffffff16111561138757601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b6000806000858060200190518101906113af919061534b565b9250925092506113c58989898689898888610458565b505050505050505050565b6113d86113e4565b6113e181612f6d565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611465576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103d3565b565b60005b60245481101561152557602260006024838154811061148b5761148b61508a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffff000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690558061151d816150b9565b91505061146a565b50611532602460006143fa565b60255460ff1660005b83518110156118c95760008482815181106115585761155861508a565b6020026020010151905060008483815181106115765761157661508a565b602002602001015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156115ec575060018460018111156115ea576115ea6154f6565b145b15611623576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061165e5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611695576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156116ff576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018082019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec40180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8581169182179092556000818152602260209081526040918290208651815488840180518a8701805163ffffffff9095167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000909416841764010000000062ffffff93841602177fffffffffff0000000000000000000000000000000000000000ffffffffffffff16670100000000000000958b16959095029490941785556060808c0180519b87019b909b556080808d018051600290980180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff998a1617905589519586529351909216968401969096529251909716948101949094529551918301919091529251909216928201929092527f720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c9060a00160405180910390a2505080806118c1906150b9565b91505061153b565b50505050565b60005b600e5481101561194657611933600e82815481106118f2576118f261508a565b600091825260209091200154601454600e5473ffffffffffffffffffffffffffffffffffffffff909216916bffffffffffffffffffffffff90911690613062565b508061193e816150b9565b9150506118d2565b5060255460009060ff16815b600e54811015611ab757600e818154811061196f5761196f61508a565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c9291849081106119ac576119ac61508a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001826001811115611a4e57611a4e6154f6565b148015611a93575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b15611aa557611aa3600f8461203a565b505b80611aaf816150b9565b915050611952565b50611ac4600d60006143fa565b611ad0600e60006143fa565b6040805160808101825260008082526020820181905291810182905260608101829052905b8551811015611f6057600c6000878381518110611b1457611b1461508a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611b7f576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16868281518110611ba957611ba961508a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611bfe576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c6000888481518110611c2f57611c2f61508a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558451859082908110611cd757611cd761508a565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611d47576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611e02576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611f3c57611f3c6154f6565b03611f4e57611f4c600f8561326a565b505b80611f58816150b9565b915050611af5565b508451611f7490600d906020880190614418565b508351611f8890600e906020870190614418565b505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611fb499989796959493929190615525565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b600061205c8373ffffffffffffffffffffffffffffffffffffffff841661328c565b90505b92915050565b600087876040516120779291906155ba565b60405190819003812061208e918b906020016155ca565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612265576001858783602081106120fa576120fa61508a565b61210791901a601b6151d8565b8c8c858181106121195761211961508a565b905060200201358b8b868181106121325761213261508a565b905060200201356040516000815260200160405260405161216f949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612191573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff808216151580855261010090920416938301939093529095509350905061223f576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061225d906150b9565b9150506120dd565b50827e010101010101010101010101010101010101010101010101010101010101018416146122c0576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6123076040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6000612315838501856156bb565b604081015151606082015151919250908114158061233857508082608001515114155b806123485750808260a001515114155b1561237f576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff8111156123a7576123a7614526565b60405190808252806020026020018201604052801561247357816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816123c55790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125359190614e7d565b9050600086610100015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa158015612589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ad9190614e7d565b905060005b866040015151811015612a3d5760046000886040015183815181106125d9576125d961508a565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106126fc576126fc61508a565b602002602001015160000181905250612731876040015182815181106127245761272461508a565b60200260200101516132db565b8582815181106127435761274361508a565b6020026020010151606001906001811115612760576127606154f6565b90816001811115612773576127736154f6565b815250506127d7876040015182815181106127905761279061508a565b602002602001015184896080015184815181106127af576127af61508a565b60200260200101518885815181106127c9576127c961508a565b60200260200101518c613386565b8683815181106127e9576127e961508a565b60200260200101516020018784815181106128065761280661508a565b602002602001015160c00182815250821515151581525050508481815181106128315761283161508a565b602002602001015160200151156128615760018460000181815161285591906157a8565b61ffff16905250612866565b612a2b565b6128cc85828151811061287b5761287b61508a565b60200260200101516000015160800151886060015183815181106128a1576128a161508a565b60200260200101518960a0015184815181106128bf576128bf61508a565b60200260200101516134a5565b8683815181106128de576128de61508a565b60200260200101516040018784815181106128fb576128fb61508a565b602002602001015160800182815250821515151581525050508760800151600161292591906151d8565b6129339060ff1660406157c3565b6103a48860a00151838151811061294c5761294c61508a565b60200260200101515161295f91906151c5565b61296991906151c5565b85828151811061297b5761297b61508a565b602002602001015160a001818152505084818151811061299d5761299d61508a565b602002602001015160a00151846060018181516129ba91906151c5565b90525084518590829081106129d1576129d161508a565b602002602001015160800151866129e891906157da565b9550612a2b87604001518281518110612a0357612a0361508a565b602002602001015184878481518110612a1e57612a1e61508a565b60200260200101516136c0565b80612a35816150b9565b9150506125b2565b50825161ffff16600003612a545750505050505050565b61c738612a623660106157c3565b5a612a6d90886157da565b612a7791906151c5565b612a8191906151c5565b835190955061232890612a989061ffff168761581c565b612aa291906151c5565b60408051606081018252600080825260208201819052918101829052919650612aca896137c5565b905060005b886040015151811015612e0657868181518110612aee57612aee61508a565b60200260200101516020015115612df457801580612b86575086612b136001836157da565b81518110612b2357612b2361508a565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612b5c57612b5c61508a565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612bba57612bb78a888381518110612ba157612ba161508a565b60200260200101516000015161010001516138b6565b92505b6000612cd88b6040518061012001604052808b8681518110612bde57612bde61508a565b60200260200101516080015181526020018c81526020018a606001518c8781518110612c0c57612c0c61508a565b602002602001015160a001518a612c2391906157c3565b612c2d919061581c565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612c5e57612c5e61508a565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612cad57612cad61508a565b60200260200101518b8681518110612cc757612cc761508a565b602002602001015160000151613a07565b9050806060015187604001818151612cf091906151a0565b6bffffffffffffffffffffffff169052506040810151602088018051612d179083906151a0565b6bffffffffffffffffffffffff169052508751889083908110612d3c57612d3c61508a565b60200260200101516040015115158a604001518381518110612d6057612d6061508a565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83606001518460400151612d9d91906151a0565b8b8681518110612daf57612daf61508a565b6020026020010151608001518d8f608001518881518110612dd257612dd261508a565b6020026020010151604051612dea9493929190615830565b60405180910390a3505b80612dfe816150b9565b915050612acf565b505050602083810151336000908152600b90925260409091208054600290612e439084906201000090046bffffffffffffffffffffffff166151a0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612ea191906151a0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612ee391906151a0565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612f5f91906151c5565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612fec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103d3565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061325e5760008160600151856130fa919061586d565b905060006131088583615892565b9050808360400181815161311c91906151a0565b6bffffffffffffffffffffffff1690525061313785826158bd565b8360600181815161314891906151a0565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b600061205c8373ffffffffffffffffffffffffffffffffffffffff8416613d03565b60008181526001830160205260408120546132d35750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561205f565b50600061205f565b6000818160045b600f811015613368577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106133205761332061508a565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461335657506000949350505050565b80613360816150b9565b9150506132e2565b5081600f1a600181111561337e5761337e6154f6565b949350505050565b6000808080856060015160018111156133a1576133a16154f6565b036133c7576133b38888888888613df6565b6133c25760009250905061349b565b61343f565b6001856060015160018111156133df576133df6154f6565b0361340d5760006133f289898988613f80565b9250905080613407575060009250905061349b565b5061343f565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061349457877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516134819190614513565b60405180910390a260009250905061349b565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff1615613502576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613577908590602401614513565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061364a90879087906004016158ed565b60408051808303816000875af1158015613668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368c9190615906565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136d8576136d86154f6565b0361373c57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b600181606001516001811115613754576137546154f6565b036137c05760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613835573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613859919061594e565b5093505092505060008213158061386f57508042105b8061389f57506000846040015162ffffff1611801561389f575061389381426157da565b846040015162ffffff16105b156138af575050601b5492915050565b5092915050565b604080516060810182526000808252602080830182815283850183905273ffffffffffffffffffffffffffffffffffffffff868116845260229092528483208054640100000000810462ffffff1690925263ffffffff8216855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495909484936701000000000000009093049092169163feaf968c9160048082019260a0929091908290030181865afa158015613978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399c919061594e565b509350509250506000821315806139b257508042105b806139e257506000866040015162ffffff161180156139e257506139d681426157da565b866040015162ffffff16105b156139f657600183015460408501526139fe565b604084018290525b50505092915050565b604080516080810182526000808252602080830182905292820181905260608201529082015115613a805760008381526023602090815260409182902082518084019093525463ffffffff811680845262ffffff640100000000909204821693830193845260e088018051919091529251925192169101525b6000613a8c868661418d565b60c0840151602082015182519293509091600091613aa9916151a0565b905082600001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff161015613b2e57819050613b0f87608001518860e0015160400151846bffffffffffffffffffffffff16613b0091906157c3565b613b0a919061581c565b614358565b6bffffffffffffffffffffffff16604084015260006060840152613bba565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff161015613bba57819050613ba683604001516bffffffffffffffffffffffff1688608001518960e0015160400151856bffffffffffffffffffffffff16613b9291906157c3565b613b9c919061581c565b613b0a91906157da565b6bffffffffffffffffffffffff1660608401525b60008681526004602052604090206001018054829190601090613c0090849070010000000000000000000000000000000090046bffffffffffffffffffffffff1661586d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008881526004602052604081206001018054928516935091613c5b9084906fffffffffffffffffffffffffffffffff1661599e565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550806bffffffffffffffffffffffff16602160008960c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613cf291906157da565b909155509298975050505050505050565b60008181526001830160205260408120548015613dec576000613d276001836157da565b8554909150600090613d3b906001906157da565b9050818114613da0576000866000018281548110613d5b57613d5b61508a565b9060005260206000200154905080876000018481548110613d7e57613d7e61508a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613db157613db16159c7565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061205f565b600091505061205f565b60008084806020019051810190613e0d91906159f6565b845160e00151815191925063ffffffff90811691161015613e6a57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613e589190614513565b60405180910390a26000915050613f77565b8260e001518015613f2a5750602081015115801590613f2a5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f279190614e7d565b14155b80613f3c5750805163ffffffff168611155b15613f7157867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613e589190614513565b60019150505b95945050505050565b600080600084806020019051810190613f999190615a4e565b9050600087826000015183602001518460400151604051602001613ffb94939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e0015180156140d657506080820151158015906140d65750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156140af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140d39190614e7d565b14155b806140eb575086826060015163ffffffff1610155b1561413557877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141209190614513565b60405180910390a26000935091506141849050565b60008181526008602052604090205460ff161561417c57877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141209190614513565b600193509150505b94509492505050565b6040805160808101825260008082526020820181905291810182905260608101919091526000836060015161ffff1683606001516141cb91906157c3565b905082610100015180156141de5750803a105b156141e657503a5b60008360a0015184604001518560200151866000015161420691906151c5565b61421090856157c3565b61421a91906151c5565b61422491906157c3565b905061423d8460e001516040015182613b0a919061581c565b6bffffffffffffffffffffffff168352608084015161426090613b0a908361581c565b6bffffffffffffffffffffffff16604084015260e0840151602001516000906142979062ffffff16683635c9adc5dea000006157c3565b9050600081633b9aca008760a001518860e001516000015163ffffffff1689604001518a60000151896142ca91906157c3565b6142d491906151c5565b6142de91906157c3565b6142e891906157c3565b6142f2919061581c565b6142fc91906151c5565b90506143158660e001516040015182613b0a919061581c565b6bffffffffffffffffffffffff166020860152608086015161433b90613b0a908361581c565b6bffffffffffffffffffffffff1660608601525050505092915050565b60006bffffffffffffffffffffffff8211156143f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016103d3565b5090565b50805460008255906000526020600020908101906113e1919061449a565b828054828255906000526020600020908101928215614492579160200282015b8281111561449257825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614438565b506143f69291505b5b808211156143f6576000815560010161449b565b6000815180845260005b818110156144d5576020818501810151868301820152016144b9565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061205c60208301846144af565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff8111828210171561457957614579614526565b60405290565b60405160a0810167ffffffffffffffff8111828210171561457957614579614526565b60405160c0810167ffffffffffffffff8111828210171561457957614579614526565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561460c5761460c614526565b604052919050565b600067ffffffffffffffff82111561462e5761462e614526565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146113e157600080fd5b803561466581614638565b919050565b600082601f83011261467b57600080fd5b8135602061469061468b83614614565b6145c5565b82815260059290921b840181019181810190868411156146af57600080fd5b8286015b848110156146d35780356146c681614638565b83529183019183016146b3565b509695505050505050565b803560ff8116811461466557600080fd5b63ffffffff811681146113e157600080fd5b8035614665816146ef565b80151581146113e157600080fd5b80356146658161470c565b62ffffff811681146113e157600080fd5b803561466581614725565b61ffff811681146113e157600080fd5b803561466581614741565b6000610200828403121561476f57600080fd5b614777614555565b905061478282614701565b815261479060208301614701565b60208201526147a160408301614701565b60408201526147b26060830161465a565b60608201526147c36080830161471a565b60808201526147d460a08301614736565b60a08201526147e560c08301614701565b60c08201526147f660e08301614701565b60e082015261010061480981840161465a565b9082015261012061481b838201614751565b9082015261014061482d83820161465a565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff81111561486e57600080fd5b61487a8582860161466a565b8284015250506101e061488e81840161465a565b9082015292915050565b803567ffffffffffffffff8116811461466557600080fd5b600082601f8301126148c157600080fd5b813567ffffffffffffffff8111156148db576148db614526565b61490c60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016145c5565b81815284602083860101111561492157600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261494f57600080fd5b8135602061495f61468b83614614565b82815260059290921b8401810191818101908684111561497e57600080fd5b8286015b848110156146d357803561499581614638565b8352918301918301614982565b6bffffffffffffffffffffffff811681146113e157600080fd5b600082601f8301126149cd57600080fd5b813560206149dd61468b83614614565b82815260a092830285018201928282019190878511156149fc57600080fd5b8387015b85811015614a7b5781818a031215614a185760008081fd5b614a2061457f565b8135614a2b816146ef565b815281860135614a3a81614725565b81870152604082810135614a4d81614638565b9082015260608281013590820152608080830135614a6a816149a2565b908201528452928401928101614a00565b5090979650505050505050565b600080600080600080600080610100898b031215614aa557600080fd5b883567ffffffffffffffff80821115614abd57600080fd5b614ac98c838d0161466a565b995060208b0135915080821115614adf57600080fd5b614aeb8c838d0161466a565b9850614af960408c016146de565b975060608b0135915080821115614b0f57600080fd5b614b1b8c838d0161475c565b9650614b2960808c01614898565b955060a08b0135915080821115614b3f57600080fd5b614b4b8c838d016148b0565b945060c08b0135915080821115614b6157600080fd5b614b6d8c838d0161493e565b935060e08b0135915080821115614b8357600080fd5b50614b908b828c016149bc565b9150509295985092959890939650565b60008083601f840112614bb257600080fd5b50813567ffffffffffffffff811115614bca57600080fd5b602083019150836020828501011115614be257600080fd5b9250929050565b60008060008060608587031215614bff57600080fd5b8435614c0a81614638565b935060208501359250604085013567ffffffffffffffff811115614c2d57600080fd5b614c3987828801614ba0565b95989497509550505050565b60008083601f840112614c5757600080fd5b50813567ffffffffffffffff811115614c6f57600080fd5b6020830191508360208260051b8501011115614be257600080fd5b60008060008060008060008060e0898b031215614ca657600080fd5b606089018a811115614cb757600080fd5b8998503567ffffffffffffffff80821115614cd157600080fd5b614cdd8c838d01614ba0565b909950975060808b0135915080821115614cf657600080fd5b614d028c838d01614c45565b909750955060a08b0135915080821115614d1b57600080fd5b50614d288b828c01614c45565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614d5a57600080fd5b863567ffffffffffffffff80821115614d7257600080fd5b614d7e8a838b0161466a565b97506020890135915080821115614d9457600080fd5b614da08a838b0161466a565b9650614dae60408a016146de565b95506060890135915080821115614dc457600080fd5b614dd08a838b016148b0565b9450614dde60808a01614898565b935060a0890135915080821115614df457600080fd5b50614e0189828a016148b0565b9150509295509295509295565b600060208284031215614e2057600080fd5b8135614e2b81614638565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff81811683821602908116908181146138af576138af614e32565b600060208284031215614e8f57600080fd5b5051919050565b63ffffffff8181168382160190808211156138af576138af614e32565b600081518084526020808501945080840160005b83811015614ef957815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614ec7565b509495945050505050565b60208152614f1b60208201835163ffffffff169052565b60006020830151614f34604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e0830151610100614fb38185018363ffffffff169052565b8401519050610120614fdc8482018373ffffffffffffffffffffffffffffffffffffffff169052565b8401519050610140614ff38482018361ffff169052565b840151905061016061501c8482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e080860182905291925090615064610220860184614eb3565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150ea576150ea614e32565b5060010190565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526151218184018a614eb3565b905082810360808401526151358189614eb3565b905060ff871660a084015282810360c084015261515281876144af565b905067ffffffffffffffff851660e084015282810361010084015261517781856144af565b9c9b505050505050505050505050565b60006020828403121561519957600080fd5b5035919050565b6bffffffffffffffffffffffff8181168382160190808211156138af576138af614e32565b8082018082111561205f5761205f614e32565b60ff818116838216019081111561205f5761205f614e32565b8051614665816146ef565b805161466581614638565b80516146658161470c565b805161466581614725565b805161466581614741565b600082601f83011261523957600080fd5b8151602061524961468b83614614565b82815260059290921b8401810191818101908684111561526857600080fd5b8286015b848110156146d357805161527f81614638565b835291830191830161526c565b600082601f83011261529d57600080fd5b815160206152ad61468b83614614565b82815260a092830285018201928282019190878511156152cc57600080fd5b8387015b85811015614a7b5781818a0312156152e85760008081fd5b6152f061457f565b81516152fb816146ef565b81528186015161530a81614725565b8187015260408281015161531d81614638565b908201526060828101519082015260808083015161533a816149a2565b9082015284529284019281016152d0565b60008060006060848603121561536057600080fd5b835167ffffffffffffffff8082111561537857600080fd5b90850190610200828803121561538d57600080fd5b615395614555565b61539e836151f1565b81526153ac602084016151f1565b60208201526153bd604084016151f1565b60408201526153ce606084016151fc565b60608201526153df60808401615207565b60808201526153f060a08401615212565b60a082015261540160c084016151f1565b60c082015261541260e084016151f1565b60e08201526101006154258185016151fc565b9082015261012061543784820161521d565b908201526101406154498482016151fc565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c0808401518381111561548257600080fd5b61548e8a828701615228565b8284015250506101e06154a28185016151fc565b9082015260208701519095509150808211156154bd57600080fd5b6154c987838801615228565b935060408601519150808211156154df57600080fd5b506154ec8682870161528c565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b16604085015281606085015261556c8285018b614eb3565b91508382036080850152615580828a614eb3565b915060ff881660a085015283820360c085015261559d82886144af565b90861660e0850152838103610100850152905061517781856144af565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f8301126155f157600080fd5b8135602061560161468b83614614565b82815260059290921b8401810191818101908684111561562057600080fd5b8286015b848110156146d35780358352918301918301615624565b600082601f83011261564c57600080fd5b8135602061565c61468b83614614565b82815260059290921b8401810191818101908684111561567b57600080fd5b8286015b848110156146d357803567ffffffffffffffff81111561569f5760008081fd5b6156ad8986838b01016148b0565b84525091830191830161567f565b6000602082840312156156cd57600080fd5b813567ffffffffffffffff808211156156e557600080fd5b9083019060c082860312156156f957600080fd5b6157016145a2565b823581526020830135602082015260408301358281111561572157600080fd5b61572d878286016155e0565b60408301525060608301358281111561574557600080fd5b615751878286016155e0565b60608301525060808301358281111561576957600080fd5b6157758782860161563b565b60808301525060a08301358281111561578d57600080fd5b6157998782860161563b565b60a08301525095945050505050565b61ffff8181168382160190808211156138af576138af614e32565b808202811582820484141761205f5761205f614e32565b8181038181111561205f5761205f614e32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261582b5761582b6157ed565b500490565b6bffffffffffffffffffffffff8516815283602082015282604082015260806060820152600061586360808301846144af565b9695505050505050565b6bffffffffffffffffffffffff8281168282160390808211156138af576138af614e32565b60006bffffffffffffffffffffffff808416806158b1576158b16157ed565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160280821691908281146158e5576158e5614e32565b505092915050565b82815260406020820152600061337e60408301846144af565b6000806040838503121561591957600080fd5b82516159248161470c565b6020939093015192949293505050565b805169ffffffffffffffffffff8116811461466557600080fd5b600080600080600060a0868803121561596657600080fd5b61596f86615934565b945060208601519350604086015192506060860151915061599260808701615934565b90509295509295909350565b6fffffffffffffffffffffffffffffffff8181168382160190808211156138af576138af614e32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215615a0857600080fd5b6040516040810181811067ffffffffffffffff82111715615a2b57615a2b614526565b6040528251615a39816146ef565b81526020928301519281019290925250919050565b600060a08284031215615a6057600080fd5b615a6861457f565b82518152602083015160208201526040830151615a84816146ef565b60408201526060830151615a97816146ef565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicA2_3\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"contractIERC20Metadata[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6101806040523480156200001257600080fd5b50604051620065e2380380620065e283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615eae620007346000396000818160be015261019101526000505060005050600050506000505060006139a301526000505060008181610db101528181610ebf01528181610fea01528181611034015281816116b601526130ce0152615eae6000f3fe6080604052600436106100bc5760003560e01c80638da5cb5b11610074578063b1dc65a41161004e578063b1dc65a4146102f6578063e3d0e71214610316578063f2fde38b14610336576100bc565b80638da5cb5b14610265578063a4c0ed3614610290578063afcb95d7146102b0576100bc565b8063349e8cca116100a5578063349e8cca1461018257806379ba5097146101d657806381ff7048146101eb576100bc565b80630870d3a114610103578063181f5a7714610123575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100fc573d6000f35b3d6000fd5b005b34801561010f57600080fd5b5061010161011e366004614c23565b610356565b34801561012f57600080fd5b5061016c6040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b6040516101799190614d9f565b60405180910390f35b34801561018e57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610179565b3480156101e257600080fd5b50610101610c97565b3480156101f757600080fd5b5061024260175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610179565b34801561027157600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101b1565b34801561029c57600080fd5b506101016102ab366004614dfb565b610d99565b3480156102bc57600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff1690820152606001610179565b34801561030257600080fd5b50610101610311366004614e9c565b6110b5565b34801561032257600080fd5b50610101610331366004614f53565b611396565b34801561034257600080fd5b50610101610351366004615020565b6113d0565b61035e6113e4565b601f8851111561039a576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103d7576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103f657506103ee866003615073565b60ff16885111155b1561042d576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051825114610468576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104728282611467565b61047c8888611a9f565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050604051806101600160405280866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866000015163ffffffff168152602001866020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200186610100015173ffffffffffffffffffffffffffffffffffffffff168152602001601660010160149054906101000a900463ffffffff1663ffffffff168152602001601660010160189054906101000a900463ffffffff1663ffffffff168152602001866040015163ffffffff16815260200186610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018660c0015163ffffffff1681526020018660e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050846101600151601981905550846101800151601a81905550846101a00151601b819055506000601660010160189054906101000a900463ffffffff169050856101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa6919061508f565b601780547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601491610b1d918591740100000000000000000000000000000000000000009004166150a8565b92506101000a81548163ffffffff021916908363ffffffff160217905550600086604051602001610b4e9190615116565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610bb3904690309074010000000000000000000000000000000000000000900463ffffffff168d8d8d878d8d612160565b601355600960008181610bc68282614677565b5050505060005b876101c0015151811015610c2057610c0d886101c001518281518110610bf557610bf561529c565b6020026020010151600961220a90919063ffffffff16565b5080610c18816152cb565b915050610bcd565b506013546017546040517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0592610c839286927401000000000000000000000000000000000000000090910463ffffffff16908f908f908f9089908f908f90615303565b60405180910390a150505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610e08576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610e42576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e5082840184615399565b6000818152600460205260409020549091506601000000000000900463ffffffff90811614610eab576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600201547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614610f2f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260046020526040902060010154610f6e90859070010000000000000000000000000000000090046bffffffffffffffffffffffff166153b2565b600082815260046020908152604080832060010180546bffffffffffffffffffffffff95909516700100000000000000000000000000000000027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff9095169490941790935573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016825260219052205461101d9085906153d7565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660009081526021602090815260409182902093909355516bffffffffffffffffffffffff871681529087169183917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203910160405180910390a35050505050565b60005a60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff16610100820152919250611219576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16611262576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548a351461129e576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101516112ae9060016153ea565b60ff16861415806112bf5750858414155b156112f6576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113068a8a8a8a8a8a8a8a612235565b60006113128a8a61249e565b905060208b0135600881901c63ffffffff1661132f848487612557565b836020015163ffffffff168163ffffffff16111561138757601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b6000806000858060200190518101906113af91906155d4565b9250925092506113c58989898689898888610356565b505050505050505050565b6113d86113e4565b6113e181613144565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611465576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610d14565b565b60005b60245481101561152557602260006024838154811061148b5761148b61529c565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690558061151d816152cb565b91505061146a565b5061153260246000614677565b60255460ff1660005b8351811015611a995760008482815181106115585761155861529c565b6020026020010151905060008483815181106115765761157661529c565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef919061577f565b60ff16816060015160ff1614158061167d5750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611651573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611675919061577f565b60ff16600814155b156116b4576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156117205750600184600181111561171e5761171e61579c565b145b15611757576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821615806117925750604081015173ffffffffffffffffffffffffffffffffffffffff16155b156117c9576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526022602052604090205467010000000000000090041615611833576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611a7c908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a250508080611a91906152cb565b91505061153b565b50505050565b60005b600e54811015611b1657611b03600e8281548110611ac257611ac261529c565b600091825260209091200154601454600e5473ffffffffffffffffffffffffffffffffffffffff909216916bffffffffffffffffffffffff90911690613239565b5080611b0e816152cb565b915050611aa2565b5060255460009060ff16815b600e54811015611c8757600e8181548110611b3f57611b3f61529c565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611b7c57611b7c61529c565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001826001811115611c1e57611c1e61579c565b148015611c63575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b15611c7557611c73600f8461220a565b505b80611c7f816152cb565b915050611b22565b50611c94600d6000614677565b611ca0600e6000614677565b6040805160808101825260008082526020820181905291810182905260608101829052905b855181101561213057600c6000878381518110611ce457611ce461529c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611d4f576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16868281518110611d7957611d7961529c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dce576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c6000888481518110611dff57611dff61529c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558451859082908110611ea757611ea761529c565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611f17576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611fd2576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169490941717919091169290921791909117905583600181111561210c5761210c61579c565b0361211e5761211c600f85613441565b505b80612128816152cb565b915050611cc5565b50845161214490600d906020880190614695565b50835161215890600e906020870190614695565b505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001612184999897969594939291906157cb565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b600061222c8373ffffffffffffffffffffffffffffffffffffffff8416613463565b90505b92915050565b60008787604051612247929190615860565b60405190819003812061225e918b90602001615870565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612435576001858783602081106122ca576122ca61529c565b6122d791901a601b6153ea565b8c8c858181106122e9576122e961529c565b905060200201358b8b868181106123025761230261529c565b905060200201356040516000815260200160405260405161233f949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612361573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff808216151580855261010090920416938301939093529095509350905061240f576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061242d906152cb565b9150506122ad565b50827e01010101010101010101010101010101010101010101010101010101010101841614612490576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6124d76040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006124e583850185615961565b604081015151606082015151919250908114158061250857508082608001515114155b806125185750808260a001515114155b1561254f576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff8111156125775761257761472c565b60405190808252806020026020018201604052801561264357816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816125955790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612705919061508f565b9050600086610100015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa158015612759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277d919061508f565b905060005b866040015151811015612c0d5760046000886040015183815181106127a9576127a961529c565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106128cc576128cc61529c565b602002602001015160000181905250612901876040015182815181106128f4576128f461529c565b60200260200101516134b2565b8582815181106129135761291361529c565b60200260200101516060019060018111156129305761293061579c565b908160018111156129435761294361579c565b815250506129a7876040015182815181106129605761296061529c565b6020026020010151848960800151848151811061297f5761297f61529c565b60200260200101518885815181106129995761299961529c565b60200260200101518c61355d565b8683815181106129b9576129b961529c565b60200260200101516020018784815181106129d6576129d661529c565b602002602001015160c0018281525082151515158152505050848181518110612a0157612a0161529c565b60200260200101516020015115612a3157600184600001818151612a259190615a4e565b61ffff16905250612a36565b612bfb565b612a9c858281518110612a4b57612a4b61529c565b6020026020010151600001516080015188606001518381518110612a7157612a7161529c565b60200260200101518960a001518481518110612a8f57612a8f61529c565b602002602001015161367c565b868381518110612aae57612aae61529c565b6020026020010151604001878481518110612acb57612acb61529c565b6020026020010151608001828152508215151515815250505087608001516001612af591906153ea565b612b039060ff166040615a69565b6103a48860a001518381518110612b1c57612b1c61529c565b602002602001015151612b2f91906153d7565b612b3991906153d7565b858281518110612b4b57612b4b61529c565b602002602001015160a0018181525050848181518110612b6d57612b6d61529c565b602002602001015160a0015184606001818151612b8a91906153d7565b9052508451859082908110612ba157612ba161529c565b60200260200101516080015186612bb89190615a80565b9550612bfb87604001518281518110612bd357612bd361529c565b602002602001015184878481518110612bee57612bee61529c565b6020026020010151613897565b80612c05816152cb565b915050612782565b50825161ffff16600003612c245750505050505050565b61c800612c32366010615a69565b5a612c3d9088615a80565b612c4791906153d7565b612c5191906153d7565b83519095506123f090612c689061ffff1687615ac2565b612c7291906153d7565b6040805160808101825260008082526020820181905291810182905260608101829052919650612ca18961399c565b905060005b886040015151811015612fdd57868181518110612cc557612cc561529c565b60200260200101516020015115612fcb57801580612d5d575086612cea600183615a80565b81518110612cfa57612cfa61529c565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612d3357612d3361529c565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612d9157612d8e8a888381518110612d7857612d7861529c565b6020026020010151600001516101000151613a8d565b92505b6000612eaf8b6040518061012001604052808b8681518110612db557612db561529c565b60200260200101516080015181526020018c81526020018a606001518c8781518110612de357612de361529c565b602002602001015160a001518a612dfa9190615a69565b612e049190615ac2565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612e3557612e3561529c565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612e8457612e8461529c565b60200260200101518b8681518110612e9e57612e9e61529c565b602002602001015160000151613c09565b9050806060015187604001818151612ec791906153b2565b6bffffffffffffffffffffffff169052506040810151602088018051612eee9083906153b2565b6bffffffffffffffffffffffff169052508751889083908110612f1357612f1361529c565b60200260200101516040015115158a604001518381518110612f3757612f3761529c565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83606001518460400151612f7491906153b2565b8b8681518110612f8657612f8661529c565b6020026020010151608001518d8f608001518881518110612fa957612fa961529c565b6020026020010151604051612fc19493929190615ad6565b60405180910390a3505b80612fd5816152cb565b915050612ca6565b505050602083810151336000908152600b9092526040909120805460029061301a9084906201000090046bffffffffffffffffffffffff166153b2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff1661307891906153b2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550826040015183602001516130ba91906153b2565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461313691906153d7565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036131c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610d14565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906134355760008160600151856132d19190615b13565b905060006132df8583615b38565b905080836040018181516132f391906153b2565b6bffffffffffffffffffffffff1690525061330e8582615b63565b8360600181815161331f91906153b2565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b600061222c8373ffffffffffffffffffffffffffffffffffffffff8416613f05565b60008181526001830160205260408120546134aa5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561222f565b50600061222f565b6000818160045b600f81101561353f577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106134f7576134f761529c565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461352d57506000949350505050565b80613537816152cb565b9150506134b9565b5081600f1a60018111156135555761355561579c565b949350505050565b6000808080856060015160018111156135785761357861579c565b0361359e5761358a8888888888613ff8565b61359957600092509050613672565b613616565b6001856060015160018111156135b6576135b661579c565b036135e45760006135c989898988614182565b92509050806135de5750600092509050613672565b50613616565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061366b57877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516136589190614d9f565b60405180910390a2600092509050613672565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156136d9576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061374e908590602401614d9f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906138219087908790600401615b93565b60408051808303816000875af115801561383f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138639190615bac565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156138af576138af61579c565b0361391357600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b60018160600151600181111561392b5761392b61579c565b036139975760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613a0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a309190615bf4565b50935050925050600082131580613a4657508042105b80613a7657506000846040015162ffffff16118015613a765750613a6a8142615a80565b846040015162ffffff16105b15613a86575050601b5492915050565b5092915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015613b7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9e9190615bf4565b50935050925050600082131580613bb457508042105b80613be457506000866040015162ffffff16118015613be45750613bd88142615a80565b866040015162ffffff16105b15613bf85760018301546060850152613c00565b606084018290525b50505092915050565b604080516080810182526000808252602080830182905292820181905260608201529082015115613c825760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613c8e868661438f565b60c0840151602082015182519293509091600091613cab916153b2565b905082600001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff161015613d3057819050613d1187608001518860e0015160600151846bffffffffffffffffffffffff16613d029190615a69565b613d0c9190615ac2565b6145d5565b6bffffffffffffffffffffffff16604084015260006060840152613dbc565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff161015613dbc57819050613da883604001516bffffffffffffffffffffffff1688608001518960e0015160600151856bffffffffffffffffffffffff16613d949190615a69565b613d9e9190615ac2565b613d0c9190615a80565b6bffffffffffffffffffffffff1660608401525b60008681526004602052604090206001018054829190601090613e0290849070010000000000000000000000000000000090046bffffffffffffffffffffffff16615b13565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008881526004602052604081206001018054928516935091613e5d9084906fffffffffffffffffffffffffffffffff16615c44565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550806bffffffffffffffffffffffff16602160008960c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613ef49190615a80565b909155509298975050505050505050565b60008181526001830160205260408120548015613fee576000613f29600183615a80565b8554909150600090613f3d90600190615a80565b9050818114613fa2576000866000018281548110613f5d57613f5d61529c565b9060005260206000200154905080876000018481548110613f8057613f8061529c565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613fb357613fb3615c6d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061222f565b600091505061222f565b6000808480602001905181019061400f9190615c9c565b845160e00151815191925063ffffffff9081169116101561406c57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88660405161405a9190614d9f565b60405180910390a26000915050614179565b8260e00151801561412c575060208101511580159061412c5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614105573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614129919061508f565b14155b8061413e5750805163ffffffff168611155b1561417357867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018660405161405a9190614d9f565b60019150505b95945050505050565b60008060008480602001905181019061419b9190615cf4565b90506000878260000151836020015184604001516040516020016141fd94939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e0015180156142d857506080820151158015906142d85750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156142b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142d5919061508f565b14155b806142ed575086826060015163ffffffff1610155b1561433757877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516143229190614d9f565b60405180910390a26000935091506143869050565b60008181526008602052604090205460ff161561437e57877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516143229190614d9f565b600193509150505b94509492505050565b60408051608081018252600080825260208201819052918101829052606081019190915260008260e001516000015160ff1690506000846060015161ffff1684606001516143dd9190615a69565b905083610100015180156143f05750803a105b156143f857503a5b60006012831161440957600161441f565b614414601284615a80565b61441f90600a615e95565b9050600060128410614432576001614448565b61443d846012615a80565b61444890600a615e95565b905060008660a0015187604001518860200151896000015161446a91906153d7565b6144749087615a69565b61447e91906153d7565b6144889190615a69565b90506144ab828860e00151606001516144a19190615a69565b613d028584615a69565b6bffffffffffffffffffffffff16865260808701516144ce90613d0c9083615ac2565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906145079062ffffff16683635c9adc5dea00000615a69565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61453a9190615a69565b61454491906153d7565b61454e9190615a69565b6145589190615a69565b6145629190615ac2565b61456c91906153d7565b905061458f848a60e00151606001516145859190615a69565b613d028784615a69565b6bffffffffffffffffffffffff16602089015260808901516145b590613d0c9083615ac2565b6bffffffffffffffffffffffff1660608901525050505050505092915050565b60006bffffffffffffffffffffffff821115614673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610d14565b5090565b50805460008255906000526020600020908101906113e19190614717565b82805482825590600052602060002090810192821561470f579160200282015b8281111561470f57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906146b5565b506146739291505b5b808211156146735760008155600101614718565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff8111828210171561477f5761477f61472c565b60405290565b60405160c0810167ffffffffffffffff8111828210171561477f5761477f61472c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156147ef576147ef61472c565b604052919050565b600067ffffffffffffffff8211156148115761481161472c565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146113e157600080fd5b80356148488161481b565b919050565b600082601f83011261485e57600080fd5b8135602061487361486e836147f7565b6147a8565b82815260059290921b8401810191818101908684111561489257600080fd5b8286015b848110156148b65780356148a98161481b565b8352918301918301614896565b509695505050505050565b60ff811681146113e157600080fd5b8035614848816148c1565b63ffffffff811681146113e157600080fd5b8035614848816148db565b80151581146113e157600080fd5b8035614848816148f8565b62ffffff811681146113e157600080fd5b803561484881614911565b61ffff811681146113e157600080fd5b80356148488161492d565b6000610200828403121561495b57600080fd5b61496361475b565b905061496e826148ed565b815261497c602083016148ed565b602082015261498d604083016148ed565b604082015261499e6060830161483d565b60608201526149af60808301614906565b60808201526149c060a08301614922565b60a08201526149d160c083016148ed565b60c08201526149e260e083016148ed565b60e08201526101006149f581840161483d565b90820152610120614a0783820161493d565b90820152610140614a1983820161483d565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff811115614a5a57600080fd5b614a668582860161484d565b8284015250506101e0614a7a81840161483d565b9082015292915050565b803567ffffffffffffffff8116811461484857600080fd5b600082601f830112614aad57600080fd5b813567ffffffffffffffff811115614ac757614ac761472c565b614af860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016147a8565b818152846020838601011115614b0d57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff811681146113e157600080fd5b600082601f830112614b5557600080fd5b81356020614b6561486e836147f7565b82815260c09283028501820192828201919087851115614b8457600080fd5b8387015b85811015614c165781818a031215614ba05760008081fd5b614ba8614785565b8135614bb3816148db565b815281860135614bc281614911565b81870152604082810135614bd58161481b565b90820152606082810135614be8816148c1565b908201526080828101359082015260a080830135614c0581614b2a565b908201528452928401928101614b88565b5090979650505050505050565b600080600080600080600080610100898b031215614c4057600080fd5b883567ffffffffffffffff80821115614c5857600080fd5b614c648c838d0161484d565b995060208b0135915080821115614c7a57600080fd5b614c868c838d0161484d565b9850614c9460408c016148d0565b975060608b0135915080821115614caa57600080fd5b614cb68c838d01614948565b9650614cc460808c01614a84565b955060a08b0135915080821115614cda57600080fd5b614ce68c838d01614a9c565b945060c08b0135915080821115614cfc57600080fd5b614d088c838d0161484d565b935060e08b0135915080821115614d1e57600080fd5b50614d2b8b828c01614b44565b9150509295985092959890939650565b6000815180845260005b81811015614d6157602081850181015186830182015201614d45565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061222c6020830184614d3b565b60008083601f840112614dc457600080fd5b50813567ffffffffffffffff811115614ddc57600080fd5b602083019150836020828501011115614df457600080fd5b9250929050565b60008060008060608587031215614e1157600080fd5b8435614e1c8161481b565b935060208501359250604085013567ffffffffffffffff811115614e3f57600080fd5b614e4b87828801614db2565b95989497509550505050565b60008083601f840112614e6957600080fd5b50813567ffffffffffffffff811115614e8157600080fd5b6020830191508360208260051b8501011115614df457600080fd5b60008060008060008060008060e0898b031215614eb857600080fd5b606089018a811115614ec957600080fd5b8998503567ffffffffffffffff80821115614ee357600080fd5b614eef8c838d01614db2565b909950975060808b0135915080821115614f0857600080fd5b614f148c838d01614e57565b909750955060a08b0135915080821115614f2d57600080fd5b50614f3a8b828c01614e57565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614f6c57600080fd5b863567ffffffffffffffff80821115614f8457600080fd5b614f908a838b0161484d565b97506020890135915080821115614fa657600080fd5b614fb28a838b0161484d565b9650614fc060408a016148d0565b95506060890135915080821115614fd657600080fd5b614fe28a838b01614a9c565b9450614ff060808a01614a84565b935060a089013591508082111561500657600080fd5b5061501389828a01614a9c565b9150509295509295509295565b60006020828403121561503257600080fd5b813561503d8161481b565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff8181168382160290811690818114613a8657613a86615044565b6000602082840312156150a157600080fd5b5051919050565b63ffffffff818116838216019080821115613a8657613a86615044565b600081518084526020808501945080840160005b8381101561510b57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016150d9565b509495945050505050565b6020815261512d60208201835163ffffffff169052565b60006020830151615146604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006151c58185018363ffffffff169052565b84015190506101206151ee8482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406152058482018361ffff169052565b840151905061016061522e8482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e0808601829052919250906152766102208601846150c5565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152fc576152fc615044565b5060010190565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526153338184018a6150c5565b9050828103608084015261534781896150c5565b905060ff871660a084015282810360c08401526153648187614d3b565b905067ffffffffffffffff851660e08401528281036101008401526153898185614d3b565b9c9b505050505050505050505050565b6000602082840312156153ab57600080fd5b5035919050565b6bffffffffffffffffffffffff818116838216019080821115613a8657613a86615044565b8082018082111561222f5761222f615044565b60ff818116838216019081111561222f5761222f615044565b8051614848816148db565b80516148488161481b565b8051614848816148f8565b805161484881614911565b80516148488161492d565b600082601f83011261544b57600080fd5b8151602061545b61486e836147f7565b82815260059290921b8401810191818101908684111561547a57600080fd5b8286015b848110156148b65780516154918161481b565b835291830191830161547e565b600082601f8301126154af57600080fd5b815160206154bf61486e836147f7565b82815260059290921b840181019181810190868411156154de57600080fd5b8286015b848110156148b65780516154f58161481b565b83529183019183016154e2565b600082601f83011261551357600080fd5b8151602061552361486e836147f7565b82815260c0928302850182019282820191908785111561554257600080fd5b8387015b85811015614c165781818a03121561555e5760008081fd5b615566614785565b8151615571816148db565b81528186015161558081614911565b818701526040828101516155938161481b565b908201526060828101516155a6816148c1565b908201526080828101519082015260a0808301516155c381614b2a565b908201528452928401928101615546565b6000806000606084860312156155e957600080fd5b835167ffffffffffffffff8082111561560157600080fd5b90850190610200828803121561561657600080fd5b61561e61475b565b61562783615403565b815261563560208401615403565b602082015261564660408401615403565b60408201526156576060840161540e565b606082015261566860808401615419565b608082015261567960a08401615424565b60a082015261568a60c08401615403565b60c082015261569b60e08401615403565b60e08201526101006156ae81850161540e565b908201526101206156c084820161542f565b908201526101406156d284820161540e565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c0808401518381111561570b57600080fd5b6157178a82870161543a565b8284015250506101e061572b81850161540e565b90820152602087015190955091508082111561574657600080fd5b6157528783880161549e565b9350604086015191508082111561576857600080fd5b5061577586828701615502565b9150509250925092565b60006020828403121561579157600080fd5b815161503d816148c1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526158128285018b6150c5565b91508382036080850152615826828a6150c5565b915060ff881660a085015283820360c08501526158438288614d3b565b90861660e085015283810361010085015290506153898185614d3b565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261589757600080fd5b813560206158a761486e836147f7565b82815260059290921b840181019181810190868411156158c657600080fd5b8286015b848110156148b657803583529183019183016158ca565b600082601f8301126158f257600080fd5b8135602061590261486e836147f7565b82815260059290921b8401810191818101908684111561592157600080fd5b8286015b848110156148b657803567ffffffffffffffff8111156159455760008081fd5b6159538986838b0101614a9c565b845250918301918301615925565b60006020828403121561597357600080fd5b813567ffffffffffffffff8082111561598b57600080fd5b9083019060c0828603121561599f57600080fd5b6159a7614785565b82358152602083013560208201526040830135828111156159c757600080fd5b6159d387828601615886565b6040830152506060830135828111156159eb57600080fd5b6159f787828601615886565b606083015250608083013582811115615a0f57600080fd5b615a1b878286016158e1565b60808301525060a083013582811115615a3357600080fd5b615a3f878286016158e1565b60a08301525095945050505050565b61ffff818116838216019080821115613a8657613a86615044565b808202811582820484141761222f5761222f615044565b8181038181111561222f5761222f615044565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615ad157615ad1615a93565b500490565b6bffffffffffffffffffffffff85168152836020820152826040820152608060608201526000615b096080830184614d3b565b9695505050505050565b6bffffffffffffffffffffffff828116828216039080821115613a8657613a86615044565b60006bffffffffffffffffffffffff80841680615b5757615b57615a93565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615b8b57615b8b615044565b505092915050565b8281526040602082015260006135556040830184614d3b565b60008060408385031215615bbf57600080fd5b8251615bca816148f8565b6020939093015192949293505050565b805169ffffffffffffffffffff8116811461484857600080fd5b600080600080600060a08688031215615c0c57600080fd5b615c1586615bda565b9450602086015193506040860151925060608601519150615c3860808701615bda565b90509295509295909350565b6fffffffffffffffffffffffffffffffff818116838216019080821115613a8657613a86615044565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215615cae57600080fd5b6040516040810181811067ffffffffffffffff82111715615cd157615cd161472c565b6040528251615cdf816148db565b81526020928301519281019290925250919050565b600060a08284031215615d0657600080fd5b60405160a0810181811067ffffffffffffffff82111715615d2957615d2961472c565b806040525082518152602083015160208201526040830151615d4a816148db565b60408201526060830151615d5d816148db565b60608201526080928301519281019290925250919050565b600181815b80851115615dce57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615db457615db4615044565b80851615615dc157918102915b93841c9390800290615d7a565b509250929050565b600082615de55750600161222f565b81615df25750600061222f565b8160018114615e085760028114615e1257615e2e565b600191505061222f565b60ff841115615e2357615e23615044565b50506001821b61222f565b5060208310610133831016604e8410600b8410161715615e51575081810a61222f565b615e5b8383615d75565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615e8d57615e8d615044565b029392505050565b600061222c8383615dd656fea164736f6c6343000813000a", } var AutomationRegistryABI = AutomationRegistryMetaData.ABI @@ -5461,7 +5462,7 @@ func (AutomationRegistryBillingConfigOverrideRemoved) Topic() common.Hash { } func (AutomationRegistryBillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") + return common.HexToHash("0xca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba3") } func (AutomationRegistryCancelledUpkeepReport) Topic() common.Hash { diff --git a/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go b/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go index 7ff232e0239..a72ff506c90 100644 --- a/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go +++ b/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go @@ -34,6 +34,7 @@ type AutomationRegistryBase23BillingConfig struct { GasFeePPB uint32 FlatFeeMilliCents *big.Int PriceFeed common.Address + Decimals uint8 FallbackPrice *big.Int MinSpend *big.Int } @@ -133,7 +134,7 @@ type IAutomationV21PlusCommonUpkeepInfoLegacy struct { } var IAutomationRegistryMaster23MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disableOffchainPayments\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedReadOnlyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackNativePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getHotVars\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyGuard\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.HotVars\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNativeUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNumUpkeeps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPayoutMode\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReorgProtectionEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getReserveAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structIAutomationV21PlusCommon.StateLegacy\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structIAutomationV21PlusCommon.OnchainConfigLegacy\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStorage\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistryBase2_3.Storage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataFixedBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataPerSignerBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structIAutomationV21PlusCommon.UpkeepInfoLegacy\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNativeTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"address[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"settleNOPsOffchain\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"supportsBillingToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disableOffchainPayments\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedReadOnlyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackNativePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getHotVars\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyGuard\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.HotVars\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNativeUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNumUpkeeps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPayoutMode\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReorgProtectionEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getReserveAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structIAutomationV21PlusCommon.StateLegacy\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structIAutomationV21PlusCommon.OnchainConfigLegacy\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStorage\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistryBase2_3.Storage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataFixedBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataPerSignerBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structIAutomationV21PlusCommon.UpkeepInfoLegacy\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNativeTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"address[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"settleNOPsOffchain\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"supportsBillingToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } var IAutomationRegistryMaster23ABI = IAutomationRegistryMaster23MetaData.ABI @@ -7070,7 +7071,7 @@ func (IAutomationRegistryMaster23BillingConfigOverrideRemoved) Topic() common.Ha } func (IAutomationRegistryMaster23BillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") + return common.HexToHash("0xca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba3") } func (IAutomationRegistryMaster23CancelledUpkeepReport) Topic() common.Hash { diff --git a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go index 79861507e14..a3ef3b83e43 100644 --- a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go +++ b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go @@ -30,15 +30,6 @@ var ( _ = abi.ConvertType ) -type VRFCoordinatorV2PlusUpgradedVersionRequestCommitment struct { - BlockNum uint64 - SubId *big.Int - CallbackGasLimit uint32 - NumWords uint32 - Sender common.Address - ExtraArgs []byte -} - type VRFProof struct { Pk [2]*big.Int Gamma [2]*big.Int @@ -51,6 +42,15 @@ type VRFProof struct { ZInv *big.Int } +type VRFTypesRequestCommitmentV2Plus struct { + BlockNum uint64 + SubId *big.Int + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + ExtraArgs []byte +} + type VRFV2PlusClientRandomWordsRequest struct { KeyHash [32]byte SubId *big.Int @@ -61,8 +61,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV2PlusUpgradedVersionMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162005e3438038062005e3483398101604081905262000034916200017e565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d3565b5050506001600160a01b0316608052620001b0565b336001600160a01b038216036200012d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019157600080fd5b81516001600160a01b0381168114620001a957600080fd5b9392505050565b608051615c61620001d3600039600081816104f401526134790152615c616000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae09540146102e057806315c48b841461030257806318e3dd271461032a5780631b6b6d2314610369578063294daa49146103965780632f622e6b146103b2578063301f42e9146103d2578063405b84fa146103f257806340d6bb821461041257806341af6c871461043d57806351cff8d91461046d5780635d06b4ab1461048d57806364d51a2a146104ad57806365982744146104c2578063689c4517146104e257806372e9d5651461051657806379ba5097146105365780637bce14d11461054b5780638402595e1461056b57806386fe91c71461058b5780638da5cb5b146105ab57806395b55cfc146105c95780639b1c385e146105dc5780639d40a6fd1461060a578063a21a23e414610637578063a4c0ed361461064c578063a63e0bfb1461066c578063aa433aff1461068c578063aefb212f146106ac578063b2a7cac5146106d9578063bec4c08c146106f9578063caf70c4a14610719578063cb63179714610739578063ce3f471914610759578063d98e620e1461076c578063dac83d291461078c578063dc311dd3146107ac578063e72f6e30146107dd578063ee9d2d38146107fd578063f2fde38b1461082a575b600080fd5b3480156101f157600080fd5b506101fa61084a565b60405161020993929190614c80565b60405180910390f35b34801561021e57600080fd5b50600c546102839061ffff81169063ffffffff62010000820481169160ff600160301b8204811692600160381b8304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e08401521661010082015261012001610209565b3480156102ec57600080fd5b506103006102fb366004614cff565b6108c6565b005b34801561030e57600080fd5b5061031760c881565b60405161ffff9091168152602001610209565b34801561033657600080fd5b50600a5461035190600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561037557600080fd5b50600254610389906001600160a01b031681565b6040516102099190614d2f565b3480156103a257600080fd5b5060405160028152602001610209565b3480156103be57600080fd5b506103006103cd366004614d43565b61090e565b3480156103de57600080fd5b506103516103ed366004614f9d565b610a5d565b3480156103fe57600080fd5b5061030061040d366004614cff565b610ef3565b34801561041e57600080fd5b506104286101f481565b60405163ffffffff9091168152602001610209565b34801561044957600080fd5b5061045d61045836600461508b565b6112b5565b6040519015158152602001610209565b34801561047957600080fd5b50610300610488366004614d43565b61145b565b34801561049957600080fd5b506103006104a8366004614d43565b6115dd565b3480156104b957600080fd5b50610317606481565b3480156104ce57600080fd5b506103006104dd3660046150a4565b611694565b3480156104ee57600080fd5b506103897f000000000000000000000000000000000000000000000000000000000000000081565b34801561052257600080fd5b50600354610389906001600160a01b031681565b34801561054257600080fd5b506103006116f4565b34801561055757600080fd5b506103006105663660046150d2565b61179e565b34801561057757600080fd5b50610300610586366004614d43565b611897565b34801561059757600080fd5b50600a54610351906001600160601b031681565b3480156105b757600080fd5b506000546001600160a01b0316610389565b6103006105d736600461508b565b6119a3565b3480156105e857600080fd5b506105fc6105f73660046150fa565b611ac4565b604051908152602001610209565b34801561061657600080fd5b5060075461062a906001600160401b031681565b6040516102099190615134565b34801561064357600080fd5b506105fc611e95565b34801561065857600080fd5b50610300610667366004615190565b612068565b34801561067857600080fd5b5061030061068736600461520e565b6121e2565b34801561069857600080fd5b506103006106a736600461508b565b6123eb565b3480156106b857600080fd5b506106cc6106c73660046152af565b612433565b604051610209919061530c565b3480156106e557600080fd5b506103006106f436600461508b565b612535565b34801561070557600080fd5b50610300610714366004614cff565b61262a565b34801561072557600080fd5b506105fc61073436600461531f565b61271c565b34801561074557600080fd5b50610300610754366004614cff565b61274c565b61030061076736600461533b565b6129b6565b34801561077857600080fd5b506105fc61078736600461508b565b612d26565b34801561079857600080fd5b506103006107a7366004614cff565b612d47565b3480156107b857600080fd5b506107cc6107c736600461508b565b612ddd565b6040516102099594939291906153b5565b3480156107e957600080fd5b506103006107f8366004614d43565b612ecb565b34801561080957600080fd5b506105fc61081836600461508b565b600f6020526000908152604090205481565b34801561083657600080fd5b50610300610845366004614d43565b613088565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff169391928391908301828280156108b457602002820191906000526020600020905b8154815260200190600101908083116108a0575b50505050509050925092509250909192565b816108d08161309c565b6108d86130fd565b6108e1836112b5565b156108ff57604051631685ecdd60e31b815260040160405180910390fd5b610909838361312a565b505050565b6109166130fd565b61091e6132cf565b600b54600160601b90046001600160601b031660000361095157604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c6109748380615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b03166109bc9190615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a36576040519150601f19603f3d011682016040523d82523d6000602084013e610a3b565b606091505b50509050806109095760405163950b247960e01b815260040160405180910390fd5b6000610a676130fd565b60005a90506000610a788686613322565b90506000856060015163ffffffff166001600160401b03811115610a9e57610a9e614d60565b604051908082528060200260200182016040528015610ac7578160200160208202803683370190505b50905060005b866060015163ffffffff16811015610b3e57826040015181604051602001610af6929190615440565b6040516020818303038152906040528051906020012060001c828281518110610b2157610b2161544e565b602090810291909101015280610b3681615464565b915050610acd565b50602080830180516000908152600f9092526040808320839055905190518291631fe543e360e01b91610b769190869060240161547d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b1790559089015160808a0151919250600091610bdb9163ffffffff169084613582565b600c805460ff60301b1916905560208a810151600090815260069091526040902054909150600160c01b90046001600160401b0316610c1b816001615496565b6020808c0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08b01518051610c68906001906154b6565b81518110610c7857610c7861544e565b602091010151600c5460f89190911c6001149150600090610ca9908a90600160581b900463ffffffff163a856135ce565b90508115610da1576020808d01516000908152600690915260409020546001600160601b03808316600160601b909204161015610cf957604051631e9acf1760e31b815260040160405180910390fd5b60208c81015160009081526006909152604090208054829190600c90610d30908490600160601b90046001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b600c8282829054906101000a90046001600160601b0316610d7891906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610e7c565b6020808d01516000908152600690915260409020546001600160601b0380831691161015610de257604051631e9acf1760e31b815260040160405180910390fd5b6020808d015160009081526006909152604081208054839290610e0f9084906001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b60008282829054906101000a90046001600160601b0316610e5791906154c9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8b6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610ed9939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b9392505050565b610efb6130fd565b610f048161361d565b610f2c5780604051635428d44960e01b8152600401610f239190614d2f565b60405180910390fd5b600080600080610f3b86612ddd565b945094505093509350336001600160a01b0316826001600160a01b031614610f9e5760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610f23565b610fa7866112b5565b15610fed5760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610f23565b60006040518060c00160405280611002600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161105691906154e9565b604051602081830303815290604052905061107088613686565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906110a99085906004016155ae565b6000604051808303818588803b1580156110c257600080fd5b505af11580156110d6573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506110ff905057506001600160601b03861615155b156111ba5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611136908a908a906004016155c1565b6020604051808303816000875af1158015611155573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117991906155e3565b6111ba5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610f23565b600c805460ff60301b1916600160301b17905560005b8351811015611263578381815181106111eb576111eb61544e565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b815260040161121e9190614d2f565b600060405180830381600087803b15801561123857600080fd5b505af115801561124c573d6000803e3d6000fd5b50505050808061125b90615464565b9150506111d0565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906112a39089908b90615600565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561133f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611321575b505050505081525050905060005b8160400151518110156114515760005b600e5481101561143e576000611407600e838154811061137f5761137f61544e565b9060005260206000200154856040015185815181106113a0576113a061544e565b60200260200101518860046000896040015189815181106113c3576113c361544e565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d825290925290205461010090046001600160401b031661382e565b506000818152600f60205260409020549091501561142b5750600195945050505050565b508061143681615464565b91505061135d565b508061144981615464565b91505061134d565b5060009392505050565b6114636130fd565b61146b6132cf565b6002546001600160a01b03166114945760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b03166000036114c057604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006114dc8380615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166115249190615420565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061157990859085906004016155c1565b6020604051808303816000875af1158015611598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bc91906155e3565b6115d957604051631e9acf1760e31b815260040160405180910390fd5b5050565b6115e56132cf565b6115ee8161361d565b1561160e578060405163ac8a27ef60e01b8152600401610f239190614d2f565b601280546001810182556000919091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611689908390614d2f565b60405180910390a150565b61169c6132cf565b6002546001600160a01b0316156116c657604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b031633146117475760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610f23565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6117a66132cf565b6040805180820182526000916117d591908490600290839083908082843760009201919091525061271c915050565b6000818152600d602052604090205490915060ff161561180b57604051634a0b8fa760e01b815260048101829052602401610f23565b6000818152600d6020526040808220805460ff19166001908117909155600e805491820181559092527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909101829055517fc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d9061188b9083815260200190565b60405180910390a15050565b61189f6132cf565b600a544790600160601b90046001600160601b0316818111156118d95780826040516354ced18160e11b8152600401610f23929190615440565b818110156109095760006118ed82846154b6565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d806000811461193c576040519150601f19603f3d011682016040523d82523d6000602084013e611941565b606091505b50509050806119635760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611994929190615600565b60405180910390a15050505050565b6119ab6130fd565b6000818152600560205260409020546001600160a01b03166119e057604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611a0f83856154c9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611a5791906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611aaa9190615619565b604051611ab8929190615440565b60405180910390a25050565b6000611ace6130fd565b6020808301356000908152600590915260409020546001600160a01b0316611b0957604051630fb532db60e11b815260040160405180910390fd5b336000908152600460209081526040808320858301358452808352928190208151606081018352905460ff811615158083526001600160401b036101008304811695840195909552600160481b9091049093169181019190915290611b89578360200135336040516379bfd40160e01b8152600401610f2392919061562c565b600c5461ffff16611ba06060860160408701615643565b61ffff161080611bc3575060c8611bbd6060860160408701615643565b61ffff16115b15611bfd57611bd86060850160408601615643565b600c5460405163539c34bb60e11b8152610f23929161ffff169060c89060040161565e565b600c5462010000900463ffffffff16611c1c608086016060870161567c565b63ffffffff161115611c6257611c38608085016060860161567c565b600c54604051637aebf00f60e11b8152610f23929162010000900463ffffffff1690600401615697565b6101f4611c7560a086016080870161567c565b63ffffffff161115611caf57611c9160a085016080860161567c565b6101f46040516311ce1afb60e21b8152600401610f23929190615697565b806020018051611cbe906156ae565b6001600160401b031690526020818101516000918291611ce69188359133918a01359061382e565b90925090506000611d02611cfd60a08901896156dc565b6138b7565b90506000611d0f82613938565b905083611d1a6139a9565b60208a0135611d2f60808c0160608d0161567c565b611d3f60a08d0160808e0161567c565b3386604051602001611d579796959493929190615722565b60405160208183030381529060405280519060200120600f600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611dce9190615643565b8e6060016020810190611de1919061567c565b8f6080016020810190611df4919061567c565b89604051611e079695949392919061576e565b60405180910390a45050336000908152600460209081526040808320898301358452825291829020855181549287015193909601516001600160401b03908116600160481b02600160481b600160881b03199190941661010002610100600160481b0319971515979097166001600160481b031990931692909217959095171617909255925050505b919050565b6000611e9f6130fd565b6007546001600160401b031633611eb76001436154b6565b6040516001600160601b0319606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150611f1c816001615496565b600780546001600160401b0319166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b9190921602176001600160c01b0316600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b03928316178355935160018301805490951691161790925592518051929493919261201a9260028501920190614b8e565b5061202a91506008905084613a2a565b50827f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161205b9190614d2f565b60405180910390a2505090565b6120706130fd565b6002546001600160a01b0316331461209b576040516344b0e3c360e01b815260040160405180910390fd5b602081146120bc57604051638129bbcd60e01b815260040160405180910390fd5b60006120ca8284018461508b565b6000818152600560205260409020549091506001600160a01b031661210257604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061212983856154c9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b031661217191906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846121c49190615619565b6040516121d2929190615440565b60405180910390a2505050505050565b6121ea6132cf565b60c861ffff8a16111561221757888960c860405163539c34bb60e11b8152600401610f239392919061565e565b6000851361223b576040516321ea67b360e11b815260048101869052602401610f23565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b90990298909816600160781b600160b81b0319600160581b90960263ffffffff60581b19600160381b90980297909716600160301b600160781b03196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f95cb2ddab6d2297c29a4861691de69b3969c464aa4a9c44258b101ff02ff375a906123d8908b908b908b908b908b908990899061ffff97909716875263ffffffff95861660208801529385166040870152919093166060850152608084019290925260ff91821660a08401521660c082015260e00190565b60405180910390a1505050505050505050565b6123f36132cf565b6000818152600560205260409020546001600160a01b03168061242957604051630fb532db60e11b815260040160405180910390fd5b6115d9828261312a565b606060006124416008613a36565b905080841061246357604051631390f2a160e01b815260040160405180910390fd5b600061246f8486615619565b90508181118061247d575083155b6124875780612489565b815b9050600061249786836154b6565b9050806001600160401b038111156124b1576124b1614d60565b6040519080825280602002602001820160405280156124da578160200160208202803683370190505b50935060005b8181101561252a576124fd6124f58883615619565b600890613a40565b85828151811061250f5761250f61544e565b602090810291909101015261252381615464565b90506124e0565b505050505b92915050565b61253d6130fd565b6000818152600560205260409020546001600160a01b03168061257357604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b031633146125ca576000828152600560205260409081902060010154905163d084e97560e01b8152610f23916001600160a01b031690600401614d2f565b600082815260056020526040908190208054336001600160a01b031991821681178355600190920180549091169055905183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ab89185916157ad565b816126348161309c565b61263c6130fd565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff161561266f5750505050565b60008481526005602052604090206002018054606319016126a3576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff1990911681178355815490810182556000828152602090200180546001600160a01b0319166001600160a01b03861617905560405185907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e19061270d908790614d2f565b60405180910390a25050505050565b60008160405160200161272f91906157ea565b604051602081830303815290604052805190602001209050919050565b816127568161309c565b61275e6130fd565b612767836112b5565b1561278557604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff166127cd5782826040516379bfd40160e01b8152600401610f2392919061562c565b60008381526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561283057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612812575b5050505050905060006001825161284791906154b6565b905060005b825181101561295257846001600160a01b03168382815181106128715761287161544e565b60200260200101516001600160a01b03160361294057600083838151811061289b5761289b61544e565b60200260200101519050806005600089815260200190815260200160002060020183815481106128cd576128cd61544e565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255888152600590915260409020600201805480612918576129186157f8565b600082815260209020810160001990810180546001600160a01b031916905501905550612952565b8061294a81615464565b91505061284c565b506001600160a01b03841660009081526004602090815260408083208884529091529081902080546001600160881b03191690555185907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a79061270d908790614d2f565b60006129c482840184615825565b9050806000015160ff166001146129fd57805160405163237d181f60e21b815260ff909116600482015260016024820152604401610f23565b8060a001516001600160601b03163414612a415760a08101516040516306acf13560e41b81523460048201526001600160601b039091166024820152604401610f23565b6020808201516000908152600590915260409020546001600160a01b031615612a7d576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612b7657604051806060016040528060011515815260200160006001600160401b0316815260200160006001600160401b03168152506004600084606001518481518110612ad957612ad961544e565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208684015182528352819020835181549385015194909201516001600160481b0319909316911515610100600160481b031916919091176101006001600160401b039485160217600160481b600160881b031916600160481b939092169290920217905580612b6e81615464565b915050612a80565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612c7592600285019290910190614b8e565b5050506080810151600a8054600090612c989084906001600160601b03166154c9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612ce491906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550612d2081602001516008613a2a90919063ffffffff16565b50505050565b600e8181548110612d3657600080fd5b600091825260209091200154905081565b81612d518161309c565b612d596130fd565b600083815260056020526040902060018101546001600160a01b03848116911614612d20576001810180546001600160a01b0319166001600160a01b03851617905560405184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612dcf90339087906157ad565b60405180910390a250505050565b600081815260056020526040812054819081906001600160a01b0316606081612e1957604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612eb157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e93575b505050505090509450945094509450945091939590929450565b612ed36132cf565b6002546001600160a01b0316612efc5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612f2d903090600401614d2f565b602060405180830381865afa158015612f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f6e9190615950565b600a549091506001600160601b031681811115612fa25780826040516354ced18160e11b8152600401610f23929190615440565b81811015610909576000612fb682846154b6565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90612fe99087908590600401615600565b6020604051808303816000875af1158015613008573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302c91906155e3565b61304957604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161307a929190615600565b60405180910390a150505050565b6130906132cf565b61309981613a4c565b50565b6000818152600560205260409020546001600160a01b0316806130d257604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146115d95780604051636c51fda960e11b8152600401610f239190614d2f565b600c54600160301b900460ff16156131285760405163769dd35360e11b815260040160405180910390fd5b565b60008061313684613686565b60025491935091506001600160a01b03161580159061315d57506001600160601b03821615155b156131fd5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061319d9086906001600160601b03871690600401615600565b6020604051808303816000875af11580156131bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e091906155e3565b6131fd57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613253576040519150601f19603f3d011682016040523d82523d6000602084013e613258565b606091505b505090508061327a5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c49060600161270d565b6000546001600160a01b031633146131285760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610f23565b6040805160608101825260008082526020820181905291810191909152600061334e846000015161271c565b6000818152600d602052604090205490915060ff1661338357604051631dfd6e1360e21b815260048101829052602401610f23565b600081856080015160405160200161339c929190615440565b60408051601f1981840301815291815281516020928301206000818152600f90935290822054909250908190036133e657604051631b44092560e11b815260040160405180910390fd5b845160208087015160408089015160608a015160808b015160a08c01519351613415978a979096959101615969565b60405160208183030381529060405280519060200120811461344a5760405163354a450b60e21b815260040160405180910390fd5b60006134598660000151613aef565b905080613511578551604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d38916134ad9190600401615134565b602060405180830381865afa1580156134ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ee9190615950565b90508061351157855160405163175dadad60e01b8152610f239190600401615134565b6000876080015182604051602001613533929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050600061355a8983613bbd565b6040805160608101825297885260208801969096529486019490945250929695505050505050565b60005a61138881101561359457600080fd5b6113888103905084604082048203116135ac57600080fd5b50823b6135b857600080fd5b60008083516020850160008789f1949350505050565b600081156135fb576011546135f49086908690600160201b900463ffffffff1686613c28565b9050613615565b601154613612908690869063ffffffff1686613cca565b90505b949350505050565b6000805b60125481101561367d57826001600160a01b0316601282815481106136485761364861544e565b6000918252602090912001546001600160a01b03160361366b5750600192915050565b8061367581615464565b915050613621565b50600092915050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b8181101561372857600460008483815481106136db576136db61544e565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120898252909252902080546001600160881b031916905561372181615464565b90506136bd565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906137606002830182614bf3565b505060008581526006602052604081205561377c600886613def565b506001600160601b038416156137cf57600a80548591906000906137aa9084906001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b038316156138275782600a600c8282829054906101000a90046001600160601b03166138029190615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613893918991849101615440565b60408051808303601f19018152919052805160209091012097909650945050505050565b60408051602081019091526000815260008290036138e4575060408051602081019091526000815261252f565b63125fa26760e31b6138f683856159bd565b6001600160e01b0319161461391e57604051632923fee760e11b815260040160405180910390fd5b61392b82600481866159ed565b810190610eec9190615a17565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161397191511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b6000466139b581613dfb565b15613a235760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1d9190615950565b91505090565b4391505090565b6000610eec8383613e1e565b600061252f825490565b6000610eec8383613e6d565b336001600160a01b03821603613a9e5760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610f23565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613afb81613dfb565b15613bae57610100836001600160401b0316613b156139a9565b613b1f91906154b6565b1180613b3b5750613b2e6139a9565b836001600160401b031610155b15613b495750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613b6d908690600401615134565b602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eec9190615950565b50506001600160401b03164090565b6000613bf18360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613e97565b60038360200151604051602001613c09929190615a62565b60408051601f1981840301815291905280516020909101209392505050565b600080613c6b6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140b292505050565b905060005a613c7a8888615619565b613c8491906154b6565b613c8e9085615a76565b90506000613ca763ffffffff871664e8d4a51000615a76565b905082613cb48284615619565b613cbe9190615619565b98975050505050505050565b600080613cd561417c565b905060008113613cfb576040516321ea67b360e11b815260048101829052602401610f23565b6000613d3d6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140b292505050565b9050600082825a613d4e8b8b615619565b613d5891906154b6565b613d629088615a76565b613d6c9190615619565b613d7e90670de0b6b3a7640000615a76565b613d889190615aa3565b90506000613da163ffffffff881664e8d4a51000615a76565b9050613db881676765c793fa10079d601b1b6154b6565b821115613dd85760405163e80fa38160e01b815260040160405180910390fd5b613de28183615619565b9998505050505050505050565b6000610eec8383614238565b600061a4b1821480613e0f575062066eed82145b8061252f57505062066eee1490565b6000818152600183016020526040812054613e655750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561252f565b50600061252f565b6000826000018281548110613e8457613e8461544e565b9060005260206000200154905092915050565b613ea089614332565b613ee95760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610f23565b613ef288614332565b613f365760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610f23565b613f3f83614332565b613f8b5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610f23565b613f9482614332565b613fdf5760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b6044820152606401610f23565b613feb878a88876143f5565b6140335760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610f23565b600061403f8a87614509565b90506000614052898b878b86898961456d565b90506000614063838d8d8a86614680565b9050808a146140a45760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610f23565b505050505050505050505050565b6000466140be81613dfb565b1561410257606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b61410b816146c0565b1561367d57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615c0d60489139604051602001614151929190615ab7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613b6d91906155ae565b600c5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a09291908290030181865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190615afd565b509450909250849150508015614227575061421e82426154b6565b8463ffffffff16105b156136155750601054949350505050565b6000818152600183016020526040812054801561432157600061425c6001836154b6565b8554909150600090614270906001906154b6565b90508181146142d55760008660000182815481106142905761429061544e565b90600052602060002001549050808760000184815481106142b3576142b361544e565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142e6576142e66157f8565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061252f565b600091505061252f565b5092915050565b80516000906401000003d019116143805760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610f23565b60208201516401000003d019116143ce5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610f23565b60208201516401000003d0199080096143ee8360005b60200201516146fa565b1492915050565b60006001600160a01b03821661443b5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610f23565b60208401516000906001161561445257601c614455565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020909101918290529293506001916144bf91869188918790615b4d565b6020604051602081039080840390855afa1580156144e1573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614511614c11565b61453e6001848460405160200161452a93929190615b6b565b60405160208183030381529060405261471e565b90505b61454a81614332565b61252f578051604080516020810192909252614566910161452a565b9050614541565b614575614c11565b825186516401000003d01991829006919006036145d45760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610f23565b6145df87898861476b565b6146245760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610f23565b61462f84868561476b565b6146755760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610f23565b613cbe868484614889565b60006002868686858760405160200161469e96959493929190615b8c565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a8214806146d257506101a482145b806146df575062aa37dc82145b806146eb575061210582145b8061252f57505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614726614c11565b61472f8261494c565b815261474461473f8260006143e4565b614987565b6020820181905260029006600103611e90576020810180516401000003d019039052919050565b6000826000036147ab5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610f23565b835160208501516000906147c190600290615be6565b156147cd57601c6147d0565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614813908390869088908790615b4d565b6020604051602081039080840390855afa158015614835573d6000803e3d6000fd5b5050506020604051035190506000866040516020016148549190615bfa565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614891614c11565b8351602080860151855191860151600093849384936148b2939091906149a7565b919450925090506401000003d01985820960011461490e5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610f23565b60405180604001604052806401000003d0198061492d5761492d615a8d565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611e9057604080516020808201939093528151808203840181529082019091528051910120614954565b600061252f8260026149a06401000003d0196001615619565b901c614a87565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a08905060006149e783838585614b21565b90985090506149f888828e88614b45565b9098509050614a0988828c87614b45565b90985090506000614a1c8d878b85614b45565b9098509050614a2d88828686614b21565b9098509050614a3e88828e89614b45565b9098509050818114614a73576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614a77565b8196505b5050505050509450945094915050565b600080614a92614c2f565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614ac4614c4d565b60208160c0846005600019fa925082600003614b175760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610f23565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614be3579160200282015b82811115614be357825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614bae565b50614bef929150614c6b565b5090565b50805460008255906000526020600020908101906130999190614c6b565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614bef5760008155600101614c6c565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015614cd157845183529383019391830191600101614cb5565b509098975050505050505050565b6001600160a01b038116811461309957600080fd5b8035611e9081614cdf565b60008060408385031215614d1257600080fd5b823591506020830135614d2481614cdf565b809150509250929050565b6001600160a01b0391909116815260200190565b600060208284031215614d5557600080fd5b8135610eec81614cdf565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715614d9857614d98614d60565b60405290565b60405161012081016001600160401b0381118282101715614d9857614d98614d60565b604051601f8201601f191681016001600160401b0381118282101715614de957614de9614d60565b604052919050565b600082601f830112614e0257600080fd5b604080519081016001600160401b0381118282101715614e2457614e24614d60565b8060405250806040840185811115614e3b57600080fd5b845b81811015614e55578035835260209283019201614e3d565b509195945050505050565b803563ffffffff81168114611e9057600080fd5b600082601f830112614e8557600080fd5b81356001600160401b03811115614e9e57614e9e614d60565b614eb1601f8201601f1916602001614dc1565b818152846020838601011115614ec657600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614ef557600080fd5b614efd614d76565b905081356001600160401b038082168214614f1757600080fd5b81835260208401356020840152614f3060408501614e60565b6040840152614f4160608501614e60565b6060840152614f5260808501614cf4565b608084015260a0840135915080821115614f6b57600080fd5b50614f7884828501614e74565b60a08301525092915050565b801515811461309957600080fd5b8035611e9081614f84565b60008060008385036101e0811215614fb457600080fd5b6101a080821215614fc457600080fd5b614fcc614d9e565b9150614fd88787614df1565b8252614fe78760408801614df1565b60208301526080860135604083015260a0860135606083015260c0860135608083015261501660e08701614cf4565b60a083015261010061502a88828901614df1565b60c084015261503d886101408901614df1565b60e0840152610180870135908301529093508401356001600160401b0381111561506657600080fd5b61507286828701614ee3565b9250506150826101c08501614f92565b90509250925092565b60006020828403121561509d57600080fd5b5035919050565b600080604083850312156150b757600080fd5b82356150c281614cdf565b91506020830135614d2481614cdf565b6000604082840312156150e457600080fd5b826040830111156150f457600080fd5b50919050565b60006020828403121561510c57600080fd5b81356001600160401b0381111561512257600080fd5b820160c08185031215610eec57600080fd5b6001600160401b0391909116815260200190565b60008083601f84011261515a57600080fd5b5081356001600160401b0381111561517157600080fd5b60208301915083602082850101111561518957600080fd5b9250929050565b600080600080606085870312156151a657600080fd5b84356151b181614cdf565b93506020850135925060408501356001600160401b038111156151d357600080fd5b6151df87828801615148565b95989497509550505050565b803561ffff81168114611e9057600080fd5b803560ff81168114611e9057600080fd5b60008060008060008060008060006101208a8c03121561522d57600080fd5b6152368a6151eb565b985061524460208b01614e60565b975061525260408b01614e60565b965061526060608b01614e60565b955060808a0135945061527560a08b01614e60565b935061528360c08b01614e60565b925061529160e08b016151fd565b91506152a06101008b016151fd565b90509295985092959850929598565b600080604083850312156152c257600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015615301578151875295820195908201906001016152e5565b509495945050505050565b602081526000610eec60208301846152d1565b60006040828403121561533157600080fd5b610eec8383614df1565b6000806020838503121561534e57600080fd5b82356001600160401b0381111561536457600080fd5b61537085828601615148565b90969095509350505050565b600081518084526020808501945080840160005b838110156153015781516001600160a01b031687529582019590820190600101615390565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a0608082018190526000906153ff9083018461537c565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160601b0382811682821603908082111561432b5761432b61540a565b918252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b6000600182016154765761547661540a565b5060010190565b82815260406020820152600061361560408301846152d1565b6001600160401b0381811683821601908082111561432b5761432b61540a565b8181038181111561252f5761252f61540a565b6001600160601b0381811683821601908082111561432b5761432b61540a565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261552e60e084018261537c565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60005b83811015615579578181015183820152602001615561565b50506000910152565b6000815180845261559a81602086016020860161555e565b601f01601f19169290920160200192915050565b602081526000610eec6020830184615582565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6000602082840312156155f557600080fd5b8151610eec81614f84565b6001600160a01b03929092168252602082015260400190565b8082018082111561252f5761252f61540a565b9182526001600160a01b0316602082015260400190565b60006020828403121561565557600080fd5b610eec826151eb565b61ffff93841681529183166020830152909116604082015260600190565b60006020828403121561568e57600080fd5b610eec82614e60565b63ffffffff92831681529116602082015260400190565b60006001600160401b038281166002600160401b031981016156d2576156d261540a565b6001019392505050565b6000808335601e198436030181126156f357600080fd5b8301803591506001600160401b0382111561570d57600080fd5b60200191503681900382131561518957600080fd5b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613de290830184615582565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613cbe60c0830184615582565b6001600160a01b0392831681529116602082015260400190565b8060005b6002811015612d205781518452602093840193909101906001016157cb565b6040810161252f82846157c7565b634e487b7160e01b600052603160045260246000fd5b80356001600160601b0381168114611e9057600080fd5b6000602080838503121561583857600080fd5b82356001600160401b038082111561584f57600080fd5b9084019060c0828703121561586357600080fd5b61586b614d76565b615874836151fd565b81528383013584820152604083013561588c81614cdf565b60408201526060830135828111156158a357600080fd5b8301601f810188136158b457600080fd5b8035838111156158c6576158c6614d60565b8060051b93506158d7868501614dc1565b818152938201860193868101908a8611156158f157600080fd5b928701925b8584101561591b578335925061590b83614cdf565b82825292870192908701906158f6565b6060850152506159309150506080840161580e565b608082015261594160a0840161580e565b60a08201529695505050505050565b60006020828403121561596257600080fd5b5051919050565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613de290830184615582565b6001600160e01b031981358181169160048510156159e55780818660040360031b1b83161692505b505092915050565b600080858511156159fd57600080fd5b83861115615a0a57600080fd5b5050820193919092039150565b600060208284031215615a2957600080fd5b604051602081016001600160401b0381118282101715615a4b57615a4b614d60565b6040528235615a5981614f84565b81529392505050565b82815260608101610eec60208301846157c7565b808202811582820484141761252f5761252f61540a565b634e487b7160e01b600052601260045260246000fd5b600082615ab257615ab2615a8d565b500490565b60008351615ac981846020880161555e565b835190830190615add81836020880161555e565b01949350505050565b80516001600160501b0381168114611e9057600080fd5b600080600080600060a08688031215615b1557600080fd5b615b1e86615ae6565b9450602086015193506040860151925060608601519150615b4160808701615ae6565b90509295509295909350565b93845260ff9290921660208401526040830152606082015260800190565b838152615b7b60208201846157c7565b606081019190915260800192915050565b868152615b9c60208201876157c7565b615ba960608201866157c7565b615bb660a08201856157c7565b615bc360e08201846157c7565b60609190911b6001600160601b0319166101208201526101340195945050505050565b600082615bf557615bf5615a8d565b500690565b615c0481836157c7565b60400191905056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxGas\",\"type\":\"uint256\"}],\"name\":\"GasPriceExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"max\",\"type\":\"uint32\"}],\"name\":\"MsgDataTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFTypes.RequestCommitmentV2Plus\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exists\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200613f3803806200613f83398101604081905262000034916200017e565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d3565b5050506001600160a01b0316608052620001b0565b336001600160a01b038216036200012d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019157600080fd5b81516001600160a01b0381168114620001a957600080fd5b9392505050565b608051615f6c620001d36000396000818161052e01526133610152615f6c6000f3fe6080604052600436106101f65760003560e01c8062012291146101fb578063043bd6ae14610228578063088070f51461024c5780630ae095401461031a57806315c48b841461033c57806318e3dd27146103645780631b6b6d23146103a3578063294daa49146103d05780632f622e6b146103ec578063301f42e91461040c578063405b84fa1461042c57806340d6bb821461044c57806341af6c871461047757806351cff8d9146104a75780635d06b4ab146104c757806364d51a2a146104e757806365982744146104fc578063689c45171461051c57806372e9d5651461055057806379ba5097146105705780637a5a2aef146105855780638402595e146105a557806386fe91c7146105c55780638da5cb5b146105e557806395b55cfc146106035780639b1c385e146106165780639d40a6fd14610636578063a21a23e414610663578063a4c0ed3614610678578063a63e0bfb14610698578063aa433aff146106b8578063aefb212f146106d8578063b2a7cac514610705578063bec4c08c14610725578063caf70c4a14610745578063cb63179714610765578063ce3f471914610785578063d98e620e14610798578063da2f2610146107b8578063dac83d2914610817578063dc311dd314610837578063e72f6e3014610868578063ee9d2d3814610888578063f2fde38b146108b5575b600080fd5b34801561020757600080fd5b506102106108d5565b60405161021f93929190614eeb565b60405180910390f35b34801561023457600080fd5b5061023e60105481565b60405190815260200161021f565b34801561025857600080fd5b50600c546102bd9061ffff81169063ffffffff62010000820481169160ff600160301b8204811692600160381b8304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e0840152166101008201526101200161021f565b34801561032657600080fd5b5061033a610335366004614f6a565b610951565b005b34801561034857600080fd5b5061035160c881565b60405161ffff909116815260200161021f565b34801561037057600080fd5b50600a5461038b90600160601b90046001600160601b031681565b6040516001600160601b03909116815260200161021f565b3480156103af57600080fd5b506002546103c3906001600160a01b031681565b60405161021f9190614f9a565b3480156103dc57600080fd5b506040516002815260200161021f565b3480156103f857600080fd5b5061033a610407366004614fae565b610999565b34801561041857600080fd5b5061038b6104273660046151fd565b610ae8565b34801561043857600080fd5b5061033a610447366004614f6a565b610e02565b34801561045857600080fd5b506104626101f481565b60405163ffffffff909116815260200161021f565b34801561048357600080fd5b506104976104923660046152eb565b6111a5565b604051901515815260200161021f565b3480156104b357600080fd5b5061033a6104c2366004614fae565b611259565b3480156104d357600080fd5b5061033a6104e2366004614fae565b6113db565b3480156104f357600080fd5b50610351606481565b34801561050857600080fd5b5061033a610517366004615304565b611492565b34801561052857600080fd5b506103c37f000000000000000000000000000000000000000000000000000000000000000081565b34801561055c57600080fd5b506003546103c3906001600160a01b031681565b34801561057c57600080fd5b5061033a6114f2565b34801561059157600080fd5b5061033a6105a0366004615332565b61159c565b3480156105b157600080fd5b5061033a6105c0366004614fae565b6116d8565b3480156105d157600080fd5b50600a5461038b906001600160601b031681565b3480156105f157600080fd5b506000546001600160a01b03166103c3565b61033a6106113660046152eb565b6117e4565b34801561062257600080fd5b5061023e61063136600461536c565b611905565b34801561064257600080fd5b50600754610656906001600160401b031681565b60405161021f91906153a6565b34801561066f57600080fd5b5061023e611cbf565b34801561068457600080fd5b5061033a610693366004615402565b611e92565b3480156106a457600080fd5b5061033a6106b3366004615480565b61200c565b3480156106c457600080fd5b5061033a6106d33660046152eb565b6122ae565b3480156106e457600080fd5b506106f86106f3366004615521565b6122f6565b60405161021f919061557e565b34801561071157600080fd5b5061033a6107203660046152eb565b6123f8565b34801561073157600080fd5b5061033a610740366004614f6a565b6124ed565b34801561075157600080fd5b5061023e610760366004615591565b6125df565b34801561077157600080fd5b5061033a610780366004614f6a565b61260f565b61033a6107933660046155ad565b612871565b3480156107a457600080fd5b5061023e6107b33660046152eb565b612bd8565b3480156107c457600080fd5b506107f86107d33660046152eb565b600d6020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b0390911660208301520161021f565b34801561082357600080fd5b5061033a610832366004614f6a565b612bf9565b34801561084357600080fd5b506108576108523660046152eb565b612c8f565b60405161021f959493929190615627565b34801561087457600080fd5b5061033a610883366004614fae565b612d7d565b34801561089457600080fd5b5061023e6108a33660046152eb565b600f6020526000908152604090205481565b3480156108c157600080fd5b5061033a6108d0366004614fae565b612f3a565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561093f57602002820191906000526020600020905b81548152602001906001019080831161092b575b50505050509050925092509250909192565b8161095b81612f4e565b610963612faf565b61096c836111a5565b1561098a57604051631685ecdd60e31b815260040160405180910390fd5b6109948383612fdc565b505050565b6109a1612faf565b6109a9613181565b600b54600160601b90046001600160601b03166000036109dc57604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c6109ff8380615692565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610a479190615692565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610ac1576040519150601f19603f3d011682016040523d82523d6000602084013e610ac6565b606091505b50509050806109945760405163950b247960e01b815260040160405180910390fd5b6000610af2612faf565b60005a9050610324361115610b2957604051630f28961b60e01b815236600482015261032460248201526044015b60405180910390fd5b6000610b3586866131d4565b90506000610b4b8583600001516020015161346b565b60408301516060888101519293509163ffffffff16806001600160401b03811115610b7857610b78614fcb565b604051908082528060200260200182016040528015610ba1578160200160208202803683370190505b50925060005b81811015610c08578281604051602001610bc29291906156b2565b6040516020818303038152906040528051906020012060001c848281518110610bed57610bed6156c0565b6020908102919091010152610c01816156d6565b9050610ba7565b5050602080850180516000908152600f9092526040822082905551610c2e908a856134b9565b60208a8101516000908152600690915260409020805491925090601890610c6490600160c01b90046001600160401b03166156ef565b82546101009290920a6001600160401b0381810219909316918316021790915560808a01516001600160a01b03166000908152600460209081526040808320828e01518452909152902080549091600991610cc791600160481b9091041661571d565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555060008960a0015160018b60a0015151610d049190615740565b81518110610d1457610d146156c0565b60209101015160f81c60011490506000610d308887848d613554565b90995090508015610d7b577f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a8760200151601054604051610d729291906156b2565b60405180910390a15b50610d8b88828c6020015161358c565b6020808b015187820151604080518781526001600160601b038d16948101949094528415159084015284151560608401528b1515608084015290917faeb4b4786571e184246d39587f659abf0e26f41f6a3358692250382c0cdb47b79060a00160405180910390a3505050505050505b9392505050565b610e0a612faf565b610e13816136df565b610e325780604051635428d44960e01b8152600401610b209190614f9a565b600080600080610e4186612c8f565b945094505093509350336001600160a01b0316826001600160a01b031614610ea45760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610b20565b610ead866111a5565b15610ef35760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610b20565b6040805160c0810182526001815260208082018990526001600160a01b03851682840152606082018490526001600160601b038088166080840152861660a083015291519091600091610f4891849101615753565b6040516020818303038152906040529050610f628861374a565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b03881690610f9b908590600401615818565b6000604051808303818588803b158015610fb457600080fd5b505af1158015610fc8573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150610ff1905057506001600160601b03861615155b156110ac5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611028908a908a9060040161582b565b6020604051808303816000875af1158015611047573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106b919061584d565b6110ac5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610b20565b600c805460ff60301b1916600160301b17905560005b8351811015611153578381815181106110dd576110dd6156c0565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016111109190614f9a565b600060405180830381600087803b15801561112a57600080fd5b505af115801561113e573d6000803e3d6000fd5b505050508061114c906156d6565b90506110c2565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906111939089908b9061586a565b60405180910390a15050505050505050565b600081815260056020526040812060020180548083036111c9575060009392505050565b60005b8181101561124e576000600460008584815481106111ec576111ec6156c0565b60009182526020808320909101546001600160a01b0316835282810193909352604091820181208982529092529020546001600160401b03600160481b90910416111561123e57506001949350505050565b611247816156d6565b90506111cc565b506000949350505050565b611261612faf565b611269613181565b6002546001600160a01b03166112925760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b03166000036112be57604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006112da8380615692565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166113229190615692565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611377908590859060040161582b565b6020604051808303816000875af1158015611396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ba919061584d565b6113d757604051631e9acf1760e31b815260040160405180910390fd5b5050565b6113e3613181565b6113ec816136df565b1561140c578060405163ac8a27ef60e01b8152600401610b209190614f9a565b601180546001810182556000919091527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611487908390614f9a565b60405180910390a150565b61149a613181565b6002546001600160a01b0316156114c457604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b031633146115455760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610b20565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6115a4613181565b6040805180820182526000916115d39190859060029083908390808284376000920191909152506125df915050565b6000818152600d602052604090205490915060ff161561160957604051634a0b8fa760e01b815260048101829052602401610b20565b60408051808201825260018082526001600160401b0385811660208085019182526000878152600d9091528581209451855492516001600160481b0319909316901515610100600160481b03191617610100929093169190910291909117909255600e805491820181559091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01829055517f9b911b2c240bfbef3b6a8f7ed6ee321d1258bb2a3fe6becab52ac1cd3210afd3906116cb9083908590615883565b60405180910390a1505050565b6116e0613181565b600a544790600160601b90046001600160601b03168181111561171a5780826040516354ced18160e11b8152600401610b209291906156b2565b8181101561099457600061172e8284615740565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d806000811461177d576040519150601f19603f3d011682016040523d82523d6000602084013e611782565b606091505b50509050806117a45760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c85836040516117d592919061586a565b60405180910390a15050505050565b6117ec612faf565b6000818152600560205260409020546001600160a01b031661182157604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611850838561589a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611898919061589a565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e9028234846118eb91906158ba565b6040516118f99291906156b2565b60405180910390a25050565b600061190f612faf565b602080830135600081815260059092526040909120546001600160a01b031661194b57604051630fb532db60e11b815260040160405180910390fd5b336000908152600460209081526040808320848452808352928190208151606081018352905460ff811615158083526001600160401b036101008304811695840195909552600160481b90910490931691810191909152906119c45782336040516379bfd40160e01b8152600401610b209291906158cd565b600c5461ffff166119db60608701604088016158e4565b61ffff1610806119fe575060c86119f860608701604088016158e4565b61ffff16115b15611a3857611a1360608601604087016158e4565b600c5460405163539c34bb60e11b8152610b20929161ffff169060c8906004016158ff565b600c5462010000900463ffffffff16611a57608087016060880161591d565b63ffffffff161115611a9d57611a73608086016060870161591d565b600c54604051637aebf00f60e11b8152610b20929162010000900463ffffffff1690600401615938565b6101f4611ab060a087016080880161591d565b63ffffffff161115611aea57611acc60a086016080870161591d565b6101f46040516311ce1afb60e21b8152600401610b20929190615938565b806020018051611af9906156ef565b6001600160401b03169052604081018051611b13906156ef565b6001600160401b031690526020810151600090611b3690873590339087906138f2565b90955090506000611b5a611b55611b5060a08a018a61594f565b61397b565b6139fc565b905085611b65613a6d565b86611b7660808b0160608c0161591d565b611b8660a08c0160808d0161591d565b3386604051602001611b9e9796959493929190615995565b60405160208183030381529060405280519060200120600f600088815260200190815260200160002081905550336001600160a01b03168588600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e89868c6040016020810190611c1191906158e4565b8d6060016020810190611c24919061591d565b8e6080016020810190611c37919061591d565b89604051611c4a969594939291906159ee565b60405180910390a4505060009283526020918252604092839020815181549383015192909401516001600160481b0319909316931515610100600160481b031916939093176101006001600160401b039283160217600160481b600160881b031916600160481b91909216021790555b919050565b6000611cc9612faf565b6007546001600160401b031633611ce1600143615740565b6040516001600160601b0319606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150611d46816001615a2d565b600780546001600160401b0319166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b9190921602176001600160c01b0316600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b039283161783559351600183018054909516911617909255925180519294939192611e449260028501920190614df9565b50611e5491506008905084613aee565b50827f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d33604051611e859190614f9a565b60405180910390a2505090565b611e9a612faf565b6002546001600160a01b03163314611ec5576040516344b0e3c360e01b815260040160405180910390fd5b60208114611ee657604051638129bbcd60e01b815260040160405180910390fd5b6000611ef4828401846152eb565b6000818152600560205260409020549091506001600160a01b0316611f2c57604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b031691869190611f53838561589a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b0316611f9b919061589a565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a828784611fee91906158ba565b604051611ffc9291906156b2565b60405180910390a2505050505050565b612014613181565b60c861ffff8a16111561204157888960c860405163539c34bb60e11b8152600401610b20939291906158ff565b60008513612065576040516321ea67b360e11b815260048101869052602401610b20565b8363ffffffff168363ffffffff1611156120965782846040516313c06e5960e11b8152600401610b20929190615938565b609b60ff831611156120c05781609b604051631d66288d60e11b8152600401610b20929190615a4d565b609b60ff821611156120ea5780609b604051631d66288d60e11b8152600401610b20929190615a4d565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b90990298909816600160781b600160b81b0319600160581b90960263ffffffff60581b19600160381b90980297909716600160301b600160781b03196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f2c6b6b12413678366b05b145c5f00745bdd00e739131ab5de82484a50c9d78b69061229b908b908b908b908b908b908b908b908b908b9061ffff99909916895263ffffffff97881660208a0152958716604089015293861660608801526080870192909252841660a086015290921660c084015260ff91821660e0840152166101008201526101200190565b60405180910390a1505050505050505050565b6122b6613181565b6000818152600560205260409020546001600160a01b0316806122ec57604051630fb532db60e11b815260040160405180910390fd5b6113d78282612fdc565b606060006123046008613afa565b905080841061232657604051631390f2a160e01b815260040160405180910390fd5b600061233284866158ba565b905081811180612340575083155b61234a578061234c565b815b9050600061235a8683615740565b9050806001600160401b0381111561237457612374614fcb565b60405190808252806020026020018201604052801561239d578160200160208202803683370190505b50935060005b818110156123ed576123c06123b888836158ba565b600890613b04565b8582815181106123d2576123d26156c0565b60209081029190910101526123e6816156d6565b90506123a3565b505050505b92915050565b612400612faf565b6000818152600560205260409020546001600160a01b03168061243657604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b0316331461248d576000828152600560205260409081902060010154905163d084e97560e01b8152610b20916001600160a01b031690600401614f9a565b600082815260056020526040908190208054336001600160a01b031991821681178355600190920180549091169055905183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c9386916118f9918591615a61565b816124f781612f4e565b6124ff612faf565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff16156125325750505050565b6000848152600560205260409020600201805460631901612566576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff1990911681178355815490810182556000828152602090200180546001600160a01b0319166001600160a01b03861617905560405185907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1906125d0908790614f9a565b60405180910390a25050505050565b6000816040516020016125f29190615a9e565b604051602081830303815290604052805190602001209050919050565b8161261981612f4e565b612621612faf565b61262a836111a5565b1561264857604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff166126905782826040516379bfd40160e01b8152600401610b209291906158cd565b6000838152600560209081526040808320600201805482518185028101850190935280835291929091908301828280156126f357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126d5575b5050505050905060006001825161270a9190615740565b905060005b825181101561281357846001600160a01b0316838281518110612734576127346156c0565b60200260200101516001600160a01b03160361280357600083838151811061275e5761275e6156c0565b6020026020010151905080600560008981526020019081526020016000206002018381548110612790576127906156c0565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558881526005909152604090206002018054806127db576127db615aac565b600082815260209020810160001990810180546001600160a01b031916905501905550612813565b61280c816156d6565b905061270f565b506001600160a01b038416600090815260046020908152604080832088845290915290819020805460ff191690555185907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906125d0908790614f9a565b600061287f82840184615ad9565b9050806000015160ff166001146128af57805160405163237d181f60e21b8152610b209190600190600401615a4d565b8060a001516001600160601b031634146128f35760a08101516040516306acf13560e41b81523460048201526001600160601b039091166024820152604401610b20565b6020808201516000908152600590915260409020546001600160a01b03161561292f576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612a2857604051806060016040528060011515815260200160006001600160401b0316815260200160006001600160401b0316815250600460008460600151848151811061298b5761298b6156c0565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208684015182528352819020835181549385015194909201516001600160481b0319909316911515610100600160481b031916919091176101006001600160401b039485160217600160481b600160881b031916600160481b939092169290920217905580612a20816156d6565b915050612932565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612b2792600285019290910190614df9565b5050506080810151600a8054600090612b4a9084906001600160601b031661589a565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612b96919061589a565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550612bd281602001516008613aee90919063ffffffff16565b50505050565b600e8181548110612be857600080fd5b600091825260209091200154905081565b81612c0381612f4e565b612c0b612faf565b600083815260056020526040902060018101546001600160a01b03848116911614612bd2576001810180546001600160a01b0319166001600160a01b03851617905560405184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612c819033908790615a61565b60405180910390a250505050565b600081815260056020526040812054819081906001600160a01b0316606081612ccb57604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612d6357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612d45575b505050505090509450945094509450945091939590929450565b612d85613181565b6002546001600160a01b0316612dae5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ddf903090600401614f9a565b602060405180830381865afa158015612dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e209190615c04565b600a549091506001600160601b031681811115612e545780826040516354ced18160e11b8152600401610b209291906156b2565b81811015610994576000612e688284615740565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90612e9b908790859060040161586a565b6020604051808303816000875af1158015612eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ede919061584d565b612efb57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b4366008482604051612f2c92919061586a565b60405180910390a150505050565b612f42613181565b612f4b81613b10565b50565b6000818152600560205260409020546001600160a01b031680612f8457604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146113d75780604051636c51fda960e11b8152600401610b209190614f9a565b600c54600160301b900460ff1615612fda5760405163769dd35360e11b815260040160405180910390fd5b565b600080612fe88461374a565b60025491935091506001600160a01b03161580159061300f57506001600160601b03821615155b156130af5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061304f9086906001600160601b0387169060040161586a565b6020604051808303816000875af115801561306e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613092919061584d565b6130af57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613105576040519150601f19603f3d011682016040523d82523d6000602084013e61310a565b606091505b505090508061312c5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4906060016125d0565b6000546001600160a01b03163314612fda5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610b20565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152600061320d84600001516125df565b6000818152600d602090815260409182902082518084019093525460ff811615158084526101009091046001600160401b0316918301919091529192509061326b57604051631dfd6e1360e21b815260048101839052602401610b20565b60008286608001516040516020016132849291906156b2565b60408051601f1981840301815291815281516020928301206000818152600f90935290822054909250908190036132ce57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516132fd978a979096959101615c1d565b6040516020818303038152906040528051906020012081146133325760405163354a450b60e21b815260040160405180910390fd5b60006133418760000151613bb3565b9050806133f9578651604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d389161339591906004016153a6565b602060405180830381865afa1580156133b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d69190615c04565b9050806133f957865160405163175dadad60e01b8152610b2091906004016153a6565b600088608001518260405160200161341b929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006134428a83613c81565b604080516060810182529788526020880196909652948601949094525092979650505050505050565b6000816001600160401b03163a11156134b157821561349457506001600160401b0381166123f2565b3a8260405163435e532d60e11b8152600401610b20929190615883565b503a92915050565b6000806000631fe543e360e01b86856040516024016134d9929190615c71565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b17905590860151608087015191925061353d9163ffffffff9091169083613cec565b600c805460ff60301b191690559695505050505050565b600080831561357357613568868685613d38565b600091509150613583565b61357e868685613e49565b915091505b94509492505050565b6000818152600660205260409020821561364b5780546001600160601b03600160601b90910481169085168110156135d757604051631e9acf1760e31b815260040160405180910390fd5b6135e18582615692565b8254600160601b600160c01b031916600160601b6001600160601b039283168102919091178455600b805488939192600c9261362192869290041661589a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050612bd2565b80546001600160601b0390811690851681101561367b57604051631e9acf1760e31b815260040160405180910390fd5b6136858582615692565b82546001600160601b0319166001600160601b03918216178355600b805487926000916136b49185911661589a565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b601154600090815b8181101561374057836001600160a01b03166011828154811061370c5761370c6156c0565b6000918252602090912001546001600160a01b031603613730575060019392505050565b613739816156d6565b90506136e7565b5060009392505050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b818110156137ec576004600084838154811061379f5761379f6156c0565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120898252909252902080546001600160881b03191690556137e5816156d6565b9050613781565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906138246002830182614e5e565b505060008581526006602052604081205561384060088661403a565b506001600160601b0384161561389357600a805485919060009061386e9084906001600160601b0316615692565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b038316156138eb5782600a600c8282829054906101000a90046001600160601b03166138c69190615692565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f1981840301815290829052805160209182012092506139579189918491016156b2565b60408051808303601f19018152919052805160209091012097909650945050505050565b60408051602081019091526000815260008290036139a857506040805160208101909152600081526123f2565b63125fa26760e31b6139ba8385615c92565b6001600160e01b031916146139e257604051632923fee760e11b815260040160405180910390fd5b6139ef8260048186615cc2565b810190610dfb9190615cec565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613a3591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613a7981614046565b15613ae75760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613abd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae19190615c04565b91505090565b4391505090565b6000610dfb8383614069565b60006123f2825490565b6000610dfb83836140b8565b336001600160a01b03821603613b625760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610b20565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613bbf81614046565b15613c7257610100836001600160401b0316613bd9613a6d565b613be39190615740565b1180613bff5750613bf2613a6d565b836001600160401b031610155b15613c0d5750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613c319086906004016153a6565b602060405180830381865afa158015613c4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190615c04565b50506001600160401b03164090565b6000613cb58360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516140e2565b60038360200151604051602001613ccd929190615d37565b60408051601f1981840301815291905280516020909101209392505050565b60005a611388811015613cfe57600080fd5b611388810390508460408204820311613d1657600080fd5b50823b613d2257600080fd5b60008083516020850160008789f1949350505050565b600080613d7b6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506142fd92505050565b905060005a600c54613d9b908890600160581b900463ffffffff166158ba565b613da59190615740565b613daf9086615d4b565b600c54909150600090613dd490600160781b900463ffffffff1664e8d4a51000615d4b565b90508415613e2057600c548190606490600160b81b900460ff16613df885876158ba565b613e029190615d4b565b613e0c9190615d78565b613e1691906158ba565b9350505050610dfb565b600c548190606490613e3c90600160b81b900460ff1682615d8c565b60ff16613df885876158ba565b600080600080613e576143d0565b9150915060008213613e7f576040516321ea67b360e11b815260048101839052602401610b20565b6000613ec16000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506142fd92505050565b9050600083825a600c54613ee3908d90600160581b900463ffffffff166158ba565b613eed9190615740565b613ef7908b615d4b565b613f0191906158ba565b613f1390670de0b6b3a7640000615d4b565b613f1d9190615d78565b600c54909150600090613f469063ffffffff600160981b8204811691600160781b900416615da5565b613f5b9063ffffffff1664e8d4a51000615d4b565b9050600085613f7283670de0b6b3a7640000615d4b565b613f7c9190615d78565b905060008915613fbd57600c548290606490613fa290600160c01b900460ff1687615d4b565b613fac9190615d78565b613fb691906158ba565b9050613ffd565b600c548290606490613fd990600160c01b900460ff1682615d8c565b613fe69060ff1687615d4b565b613ff09190615d78565b613ffa91906158ba565b90505b676765c793fa10079d601b1b8111156140295760405163e80fa38160e01b815260040160405180910390fd5b9b949a509398505050505050505050565b6000610dfb8383614497565b600061a4b182148061405a575062066eed82145b806123f257505062066eee1490565b60008181526001830160205260408120546140b0575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556123f2565b5060006123f2565b60008260000182815481106140cf576140cf6156c0565b9060005260206000200154905092915050565b6140eb89614591565b6141345760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610b20565b61413d88614591565b6141815760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610b20565b61418a83614591565b6141d65760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610b20565b6141df82614591565b61422a5760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b6044820152606401610b20565b614236878a8887614654565b61427e5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610b20565b600061428a8a87614768565b9050600061429d898b878b8689896147cc565b905060006142ae838d8d8a866148eb565b9050808a146142ef5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b20565b505050505050505050505050565b60004661430981614046565b1561434d57606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c4e573d6000803e3d6000fd5b6143568161492b565b156143c757600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615f186048913960405160200161439c929190615dc2565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613c319190615818565b50600092915050565b600c5460035460408051633fabe5a360e21b815290516000938493600160381b90910463ffffffff169284926001600160a01b039092169163feaf968c9160048082019260a0929091908290030181865afa158015614433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144579190615e08565b50919650909250505063ffffffff821615801590614483575061447a8142615740565b8263ffffffff16105b925082156144915760105493505b50509091565b600081815260018301602052604081205480156145805760006144bb600183615740565b85549091506000906144cf90600190615740565b90508181146145345760008660000182815481106144ef576144ef6156c0565b9060005260206000200154905080876000018481548110614512576145126156c0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061454557614545615aac565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506123f2565b60009150506123f2565b5092915050565b80516000906401000003d019116145df5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610b20565b60208201516401000003d0191161462d5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610b20565b60208201516401000003d01990800961464d8360005b6020020151614965565b1492915050565b60006001600160a01b03821661469a5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610b20565b6020840151600090600116156146b157601c6146b4565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe199182039250600091908909875160408051600080825260209091019182905292935060019161471e91869188918790615e58565b6020604051602081039080840390855afa158015614740573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614770614e7c565b61479d6001848460405160200161478993929190615e76565b604051602081830303815290604052614989565b90505b6147a981614591565b6123f25780516040805160208101929092526147c59101614789565b90506147a0565b6147d4614e7c565b825186516401000003d01991829006919006036148335760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610b20565b61483e8789886149d6565b6148835760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610b20565b61488e8486856149d6565b6148d45760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610b20565b6148df868484614af4565b98975050505050505050565b60006002868686858760405160200161490996959493929190615e97565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a82148061493d57506101a482145b8061494a575062aa37dc82145b80614956575061210582145b806123f257505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614991614e7c565b61499a82614bb7565b81526149af6149aa826000614643565b614bf2565b6020820181905260029006600103611cba576020810180516401000003d019039052919050565b600082600003614a165760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610b20565b83516020850151600090614a2c90600290615ef1565b15614a3857601c614a3b565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614a7e908390869088908790615e58565b6020604051602081039080840390855afa158015614aa0573d6000803e3d6000fd5b505050602060405103519050600086604051602001614abf9190615f05565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614afc614e7c565b835160208086015185519186015160009384938493614b1d93909190614c12565b919450925090506401000003d019858209600114614b795760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610b20565b60405180604001604052806401000003d01980614b9857614b98615d62565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611cba57604080516020808201939093528151808203840181529082019091528051910120614bbf565b60006123f2826002614c0b6401000003d01960016158ba565b901c614cf2565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614c5283838585614d8c565b9098509050614c6388828e88614db0565b9098509050614c7488828c87614db0565b90985090506000614c878d878b85614db0565b9098509050614c9888828686614d8c565b9098509050614ca988828e89614db0565b9098509050818114614cde576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614ce2565b8196505b5050505050509450945094915050565b600080614cfd614e9a565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614d2f614eb8565b60208160c0846005600019fa925082600003614d825760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610b20565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614e4e579160200282015b82811115614e4e57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614e19565b50614e5a929150614ed6565b5090565b5080546000825590600052602060002090810190612f4b9190614ed6565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614e5a5760008155600101614ed7565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015614f3c57845183529383019391830191600101614f20565b509098975050505050505050565b6001600160a01b0381168114612f4b57600080fd5b8035611cba81614f4a565b60008060408385031215614f7d57600080fd5b823591506020830135614f8f81614f4a565b809150509250929050565b6001600160a01b0391909116815260200190565b600060208284031215614fc057600080fd5b8135610dfb81614f4a565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b038111828210171561500357615003614fcb565b60405290565b60405161012081016001600160401b038111828210171561500357615003614fcb565b604051601f8201601f191681016001600160401b038111828210171561505457615054614fcb565b604052919050565b600082601f83011261506d57600080fd5b604080519081016001600160401b038111828210171561508f5761508f614fcb565b80604052508060408401858111156150a657600080fd5b845b818110156150c05780358352602092830192016150a8565b509195945050505050565b80356001600160401b0381168114611cba57600080fd5b803563ffffffff81168114611cba57600080fd5b600060c0828403121561510857600080fd5b615110614fe1565b905061511b826150cb565b815260208083013581830152615133604084016150e2565b6040830152615144606084016150e2565b6060830152608083013561515781614f4a565b608083015260a08301356001600160401b038082111561517657600080fd5b818501915085601f83011261518a57600080fd5b81358181111561519c5761519c614fcb565b6151ae601f8201601f1916850161502c565b915080825286848285010111156151c457600080fd5b80848401858401376000848284010152508060a085015250505092915050565b8015158114612f4b57600080fd5b8035611cba816151e4565b60008060008385036101e081121561521457600080fd5b6101a08082121561522457600080fd5b61522c615009565b9150615238878761505c565b8252615247876040880161505c565b60208301526080860135604083015260a0860135606083015260c0860135608083015261527660e08701614f5f565b60a083015261010061528a8882890161505c565b60c084015261529d88610140890161505c565b60e0840152610180870135908301529093508401356001600160401b038111156152c657600080fd5b6152d2868287016150f6565b9250506152e26101c085016151f2565b90509250925092565b6000602082840312156152fd57600080fd5b5035919050565b6000806040838503121561531757600080fd5b823561532281614f4a565b91506020830135614f8f81614f4a565b6000806060838503121561534557600080fd5b604083018481111561535657600080fd5b839250615362816150cb565b9150509250929050565b60006020828403121561537e57600080fd5b81356001600160401b0381111561539457600080fd5b820160c08185031215610dfb57600080fd5b6001600160401b0391909116815260200190565b60008083601f8401126153cc57600080fd5b5081356001600160401b038111156153e357600080fd5b6020830191508360208285010111156153fb57600080fd5b9250929050565b6000806000806060858703121561541857600080fd5b843561542381614f4a565b93506020850135925060408501356001600160401b0381111561544557600080fd5b615451878288016153ba565b95989497509550505050565b803561ffff81168114611cba57600080fd5b803560ff81168114611cba57600080fd5b60008060008060008060008060006101208a8c03121561549f57600080fd5b6154a88a61545d565b98506154b660208b016150e2565b97506154c460408b016150e2565b96506154d260608b016150e2565b955060808a013594506154e760a08b016150e2565b93506154f560c08b016150e2565b925061550360e08b0161546f565b91506155126101008b0161546f565b90509295985092959850929598565b6000806040838503121561553457600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561557357815187529582019590820190600101615557565b509495945050505050565b602081526000610dfb6020830184615543565b6000604082840312156155a357600080fd5b610dfb838361505c565b600080602083850312156155c057600080fd5b82356001600160401b038111156155d657600080fd5b6155e2858286016153ba565b90969095509350505050565b600081518084526020808501945080840160005b838110156155735781516001600160a01b031687529582019590820190600101615602565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615671908301846155ee565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160601b0382811682821603908082111561458a5761458a61567c565b918252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b6000600182016156e8576156e861567c565b5060010190565b60006001600160401b038281166002600160401b031981016157135761571361567c565b6001019392505050565b60006001600160401b038216806157365761573661567c565b6000190192915050565b818103818111156123f2576123f261567c565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261579860e08401826155ee565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60005b838110156157e35781810151838201526020016157cb565b50506000910152565b600081518084526158048160208601602086016157c8565b601f01601f19169290920160200192915050565b602081526000610dfb60208301846157ec565b6001600160a01b039290921682526001600160601b0316602082015260400190565b60006020828403121561585f57600080fd5b8151610dfb816151e4565b6001600160a01b03929092168252602082015260400190565b9182526001600160401b0316602082015260400190565b6001600160601b0381811683821601908082111561458a5761458a61567c565b808201808211156123f2576123f261567c565b9182526001600160a01b0316602082015260400190565b6000602082840312156158f657600080fd5b610dfb8261545d565b61ffff93841681529183166020830152909116604082015260600190565b60006020828403121561592f57600080fd5b610dfb826150e2565b63ffffffff92831681529116602082015260400190565b6000808335601e1984360301811261596657600080fd5b8301803591506001600160401b0382111561598057600080fd5b6020019150368190038213156153fb57600080fd5b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906159e1908301846157ec565b9998505050505050505050565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a08301526148df60c08301846157ec565b6001600160401b0381811683821601908082111561458a5761458a61567c565b60ff92831681529116602082015260400190565b6001600160a01b0392831681529116602082015260400190565b8060005b6002811015612bd2578151845260209384019390910190600101615a7f565b604081016123f28284615a7b565b634e487b7160e01b600052603160045260246000fd5b80356001600160601b0381168114611cba57600080fd5b60006020808385031215615aec57600080fd5b82356001600160401b0380821115615b0357600080fd5b9084019060c08287031215615b1757600080fd5b615b1f614fe1565b615b288361546f565b815283830135848201526040830135615b4081614f4a565b6040820152606083013582811115615b5757600080fd5b8301601f81018813615b6857600080fd5b803583811115615b7a57615b7a614fcb565b8060051b9350615b8b86850161502c565b818152938201860193868101908a861115615ba557600080fd5b928701925b85841015615bcf5783359250615bbf83614f4a565b8282529287019290870190615baa565b606085015250615be491505060808401615ac2565b6080820152615bf560a08401615ac2565b60a08201529695505050505050565b600060208284031215615c1657600080fd5b5051919050565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906159e1908301846157ec565b828152604060208201526000615c8a6040830184615543565b949350505050565b6001600160e01b03198135818116916004851015615cba5780818660040360031b1b83161692505b505092915050565b60008085851115615cd257600080fd5b83861115615cdf57600080fd5b5050820193919092039150565b600060208284031215615cfe57600080fd5b604051602081016001600160401b0381118282101715615d2057615d20614fcb565b6040528235615d2e816151e4565b81529392505050565b82815260608101610dfb6020830184615a7b565b80820281158282048414176123f2576123f261567c565b634e487b7160e01b600052601260045260246000fd5b600082615d8757615d87615d62565b500490565b60ff81811683821601908111156123f2576123f261567c565b63ffffffff82811682821603908082111561458a5761458a61567c565b60008351615dd48184602088016157c8565b835190830190615de88183602088016157c8565b01949350505050565b80516001600160501b0381168114611cba57600080fd5b600080600080600060a08688031215615e2057600080fd5b615e2986615df1565b9450602086015193506040860151925060608601519150615e4c60808701615df1565b90509295509295909350565b93845260ff9290921660208401526040830152606082015260800190565b838152615e866020820184615a7b565b606081019190915260800192915050565b868152615ea76020820187615a7b565b615eb46060820186615a7b565b615ec160a0820185615a7b565b615ece60e0820184615a7b565b60609190911b6001600160601b0319166101208201526101340195945050505050565b600082615f0057615f00615d62565b500690565b615f0f8183615a7b565b60400191905056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var VRFCoordinatorV2PlusUpgradedVersionABI = VRFCoordinatorV2PlusUpgradedVersionMetaData.ABI @@ -559,6 +559,28 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionC return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SCurrentSubNonce(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) } +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_fallbackWeiPerUnitLink") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) SFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFallbackWeiPerUnitLink(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCallerSession) SFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFallbackWeiPerUnitLink(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) +} + func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SProvingKeyHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { var out []interface{} err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_provingKeyHashes", arg0) @@ -581,6 +603,36 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionC return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeyHashes(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) } +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (SProvingKeys, + + error) { + var out []interface{} + err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_provingKeys", arg0) + + outstruct := new(SProvingKeys) + if err != nil { + return *outstruct, err + } + + outstruct.Exists = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.MaxGas = *abi.ConvertType(out[1], new(uint64)).(*uint64) + + return *outstruct, err + +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) SProvingKeys(arg0 [32]byte) (SProvingKeys, + + error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeys(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCallerSession) SProvingKeys(arg0 [32]byte) (SProvingKeys, + + error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeys(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) +} + func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SRequestCommitments(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { var out []interface{} err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_requestCommitments", arg0) @@ -707,16 +759,16 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionT return _VRFCoordinatorV2PlusUpgradedVersion.Contract.CreateSubscription(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorV2PlusUpgradedVersionRequestCommitment, arg2 bool) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "fulfillRandomWords", proof, rc, arg2) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "fulfillRandomWords", proof, rc, onlyPremium) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorV2PlusUpgradedVersionRequestCommitment, arg2 bool) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.FulfillRandomWords(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, proof, rc, arg2) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) FulfillRandomWords(proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.FulfillRandomWords(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, proof, rc, onlyPremium) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorV2PlusUpgradedVersionRequestCommitment, arg2 bool) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.FulfillRandomWords(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, proof, rc, arg2) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) FulfillRandomWords(proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.FulfillRandomWords(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, proof, rc, onlyPremium) } func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) FundSubscriptionWithNative(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { @@ -815,16 +867,16 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionT return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterMigratableCoordinator(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, target) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "registerProvingKey", publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int, maxGas uint64) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "registerProvingKey", publicProvingKey, maxGas) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) RegisterProvingKey(publicProvingKey [2]*big.Int, maxGas uint64) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey, maxGas) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) RegisterProvingKey(publicProvingKey [2]*big.Int, maxGas uint64) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey, maxGas) } func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { @@ -984,14 +1036,16 @@ func (it *VRFCoordinatorV2PlusUpgradedVersionConfigSetIterator) Close() error { } type VRFCoordinatorV2PlusUpgradedVersionConfigSet struct { - MinimumRequestConfirmations uint16 - MaxGasLimit uint32 - StalenessSeconds uint32 - GasAfterPaymentCalculation uint32 - FallbackWeiPerUnitLink *big.Int - NativePremiumPercentage uint8 - LinkPremiumPercentage uint8 - Raw types.Log + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 + FallbackWeiPerUnitLink *big.Int + FulfillmentFlatFeeNativePPM uint32 + FulfillmentFlatFeeLinkDiscountPPM uint32 + NativePremiumPercentage uint8 + LinkPremiumPercentage uint8 + Raw types.Log } func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionConfigSetIterator, error) { @@ -1163,6 +1217,124 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionF return event, nil } +type VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator struct { + Event *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed struct { + RequestId *big.Int + FallbackWeiPerUnitLink *big.Int + Raw types.Log +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterFallbackWeiPerUnitLinkUsed(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator, error) { + + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.FilterLogs(opts, "FallbackWeiPerUnitLinkUsed") + if err != nil { + return nil, err + } + return &VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator{contract: _VRFCoordinatorV2PlusUpgradedVersion.contract, event: "FallbackWeiPerUnitLinkUsed", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) WatchFallbackWeiPerUnitLinkUsed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) (event.Subscription, error) { + + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.WatchLogs(opts, "FallbackWeiPerUnitLinkUsed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) + if err := _VRFCoordinatorV2PlusUpgradedVersion.contract.UnpackLog(event, "FallbackWeiPerUnitLinkUsed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) ParseFallbackWeiPerUnitLinkUsed(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed, error) { + event := new(VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) + if err := _VRFCoordinatorV2PlusUpgradedVersion.contract.UnpackLog(event, "FallbackWeiPerUnitLinkUsed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type VRFCoordinatorV2PlusUpgradedVersionFundsRecoveredIterator struct { Event *VRFCoordinatorV2PlusUpgradedVersionFundsRecovered @@ -1851,6 +2023,7 @@ func (it *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator) Close type VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered struct { KeyHash [32]byte + MaxGas uint64 Raw types.Log } @@ -1967,46 +2140,48 @@ func (it *VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator) Close } type VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled struct { - RequestId *big.Int - OutputSeed *big.Int - SubID *big.Int - Payment *big.Int - Success bool - Raw types.Log + RequestId *big.Int + OutputSeed *big.Int + SubId *big.Int + Payment *big.Int + NativePayment bool + Success bool + OnlyPremium bool + Raw types.Log } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int, subID []*big.Int) (*VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator, error) { +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int, subId []*big.Int) (*VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator, error) { var requestIdRule []interface{} for _, requestIdItem := range requestId { requestIdRule = append(requestIdRule, requestIdItem) } - var subIDRule []interface{} - for _, subIDItem := range subID { - subIDRule = append(subIDRule, subIDItem) + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) } - logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule, subIDRule) + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule, subIdRule) if err != nil { return nil, err } return &VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator{contract: _VRFCoordinatorV2PlusUpgradedVersion.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, requestId []*big.Int, subID []*big.Int) (event.Subscription, error) { +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, requestId []*big.Int, subId []*big.Int) (event.Subscription, error) { var requestIdRule []interface{} for _, requestIdItem := range requestId { requestIdRule = append(requestIdRule, requestIdItem) } - var subIDRule []interface{} - for _, subIDItem := range subID { - subIDRule = append(subIDRule, subIDItem) + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) } - logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.WatchLogs(opts, "RandomWordsFulfilled", requestIdRule, subIDRule) + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.WatchLogs(opts, "RandomWordsFulfilled", requestIdRule, subIdRule) if err != nil { return nil, err } @@ -3250,6 +3425,10 @@ type SConfig struct { NativePremiumPercentage uint8 LinkPremiumPercentage uint8 } +type SProvingKeys struct { + Exists bool + MaxGas uint64 +} func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersion) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { @@ -3257,6 +3436,8 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersion) return _VRFCoordinatorV2PlusUpgradedVersion.ParseConfigSet(log) case _VRFCoordinatorV2PlusUpgradedVersion.abi.Events["CoordinatorRegistered"].ID: return _VRFCoordinatorV2PlusUpgradedVersion.ParseCoordinatorRegistered(log) + case _VRFCoordinatorV2PlusUpgradedVersion.abi.Events["FallbackWeiPerUnitLinkUsed"].ID: + return _VRFCoordinatorV2PlusUpgradedVersion.ParseFallbackWeiPerUnitLinkUsed(log) case _VRFCoordinatorV2PlusUpgradedVersion.abi.Events["FundsRecovered"].ID: return _VRFCoordinatorV2PlusUpgradedVersion.ParseFundsRecovered(log) case _VRFCoordinatorV2PlusUpgradedVersion.abi.Events["MigrationCompleted"].ID: @@ -3296,13 +3477,17 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersion) } func (VRFCoordinatorV2PlusUpgradedVersionConfigSet) Topic() common.Hash { - return common.HexToHash("0x95cb2ddab6d2297c29a4861691de69b3969c464aa4a9c44258b101ff02ff375a") + return common.HexToHash("0x2c6b6b12413678366b05b145c5f00745bdd00e739131ab5de82484a50c9d78b6") } func (VRFCoordinatorV2PlusUpgradedVersionCoordinatorRegistered) Topic() common.Hash { return common.HexToHash("0xb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af01625") } +func (VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) Topic() common.Hash { + return common.HexToHash("0x6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a") +} + func (VRFCoordinatorV2PlusUpgradedVersionFundsRecovered) Topic() common.Hash { return common.HexToHash("0x59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600") } @@ -3324,11 +3509,11 @@ func (VRFCoordinatorV2PlusUpgradedVersionOwnershipTransferred) Topic() common.Ha } func (VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered) Topic() common.Hash { - return common.HexToHash("0xc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d") + return common.HexToHash("0x9b911b2c240bfbef3b6a8f7ed6ee321d1258bb2a3fe6becab52ac1cd3210afd3") } func (VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled) Topic() common.Hash { - return common.HexToHash("0x49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa7") + return common.HexToHash("0xaeb4b4786571e184246d39587f659abf0e26f41f6a3358692250382c0cdb47b7") } func (VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested) Topic() common.Hash { @@ -3406,8 +3591,14 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { SCurrentSubNonce(opts *bind.CallOpts) (uint64, error) + SFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) + SProvingKeyHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) + SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (SProvingKeys, + + error) + SRequestCommitments(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) STotalBalance(opts *bind.CallOpts) (*big.Int, error) @@ -3424,7 +3615,7 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) - FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorV2PlusUpgradedVersionRequestCommitment, arg2 bool) (*types.Transaction, error) + FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) FundSubscriptionWithNative(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) @@ -3442,7 +3633,7 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) - RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) + RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int, maxGas uint64) (*types.Transaction, error) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) @@ -3472,6 +3663,12 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { ParseCoordinatorRegistered(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionCoordinatorRegistered, error) + FilterFallbackWeiPerUnitLinkUsed(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsedIterator, error) + + WatchFallbackWeiPerUnitLinkUsed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed) (event.Subscription, error) + + ParseFallbackWeiPerUnitLinkUsed(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionFallbackWeiPerUnitLinkUsed, error) + FilterFundsRecovered(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionFundsRecoveredIterator, error) WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionFundsRecovered) (event.Subscription, error) @@ -3508,9 +3705,9 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered, error) - FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int, subID []*big.Int) (*VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator, error) + FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int, subId []*big.Int) (*VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilledIterator, error) - WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, requestId []*big.Int, subID []*big.Int) (event.Subscription, error) + WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, requestId []*big.Int, subId []*big.Int) (event.Subscription, error) ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go index 897e4550adc..97143c3f30b 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go @@ -31,8 +31,8 @@ var ( ) var VRFV2PlusWrapperMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedMinimumLength\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"actualLength\",\"type\":\"uint16\"}],\"name\":\"IncorrectExtraArgsLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LINKPaymentInRequestRandomWordsInNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativePaymentInOnTokenTransfer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIdMissing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Disabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Enabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"FulfillmentTxSizeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isLinkMode\",\"type\":\"bool\"}],\"name\":\"checkPaymentMode\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"wrapperNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"wrapperLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"link\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkNativeFeed\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"requestGasPrice\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"_stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"_fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60e06040526006805463ffffffff60401b191669024400000000000000001790553480156200002d57600080fd5b5060405162003cc838038062003cc88339810160408190526200005091620002a1565b813380600081620000a85760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000db57620000db81620001d9565b5050506001600160a01b038116620001065760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392831617905584811660a052831660c0526000819003620001505760405163a81c0bef60e01b815260040160405180910390fd5b60025460405163dc311dd360e01b8152600481018390526001600160a01b039091169063dc311dd390602401600060405180830381865afa1580156200019a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001c4919081019062000321565b505050608092909252506200044a9350505050565b336001600160a01b03821603620002335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200029c57600080fd5b919050565b60008060008060808587031215620002b857600080fd5b620002c38562000284565b9350620002d36020860162000284565b9250620002e36040860162000284565b6060959095015193969295505050565b80516001600160601b03811681146200029c57600080fd5b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156200033a57600080fd5b6200034586620002f3565b9450602062000356818801620002f3565b60408801519095506001600160401b0380821682146200037557600080fd5b8195506200038660608a0162000284565b945060808901519150808211156200039d57600080fd5b818901915089601f830112620003b257600080fd5b815181811115620003c757620003c76200030b565b8060051b604051601f19603f83011681018181108582111715620003ef57620003ef6200030b565b60405291825284820192508381018501918c8311156200040e57600080fd5b938501935b828510156200043757620004278562000284565b8452938501939285019262000413565b8096505050505050509295509295909350565b60805160a05160c051613824620004a46000396000818161037e01526122c90152600081816102ca0152818161123b0152818161130a0152611cb401526000818161020b015281816119090152611ea101526138246000f3fe6080604052600436106101c15760003560e01c806357a8070a116100f7578063a4c0ed3611610095578063cdd8d88511610064578063cdd8d88514610747578063e1cab74514610785578063f2fde38b146107a5578063fc2a88c3146107c557600080fd5b8063a4c0ed36146105b9578063a608a1e1146105d9578063bf17e5591461060c578063c3f909d41461062c57600080fd5b80638ea98117116100d15780638ea98117146105445780639cfc058e146105645780639eccacf614610577578063a3907d71146105a457600080fd5b806357a8070a146104c257806379ba5097146105045780638da5cb5b1461051957600080fd5b806321f25aa1116101645780632f2770db1161013e5780632f2770db146103a25780632f622e6b146103b757806348baa1c5146103d757806351cff8d9146104a257600080fd5b806321f25aa11461032f57806327e5c50a1461034f5780632808e6c81461036f57600080fd5b8063181f5a77116101a0578063181f5a771461024d57806318b6f4c8146102995780631c4695f4146102bb5780631fe543e31461030f57600080fd5b806226501b146101c6578063030932bb146101f957806313c34b7f1461022d575b600080fd5b3480156101d257600080fd5b506101e66101e1366004612e4d565b6107db565b6040519081526020015b60405180910390f35b34801561020557600080fd5b506101e67f000000000000000000000000000000000000000000000000000000000000000081565b34801561023957600080fd5b506101e6610248366004612e89565b610915565b34801561025957600080fd5b50604080518082018252601681527f5652465632506c75735772617070657220312e302e3000000000000000000000602082015290516101f09190612f20565b3480156102a557600080fd5b506102b96102b436600461301b565b610a3c565b005b3480156102c757600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b34801561031b57600080fd5b506102b961032a36600461306d565b610bbb565b34801561033b57600080fd5b506102b961034a36600461310f565b610c39565b34801561035b57600080fd5b506101e661036a366004612e89565b610f34565b34801561037b57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102ea565b3480156103ae57600080fd5b506102b9611068565b3480156103c357600080fd5b506102b96103d23660046131f1565b6110db565b3480156103e357600080fd5b506104616103f236600461320c565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810463ffffffff16907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1683565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff909216602084015267ffffffffffffffff16908201526060016101f0565b3480156104ae57600080fd5b506102b96104bd3660046131f1565b611202565b3480156104ce57600080fd5b506002546104f49074010000000000000000000000000000000000000000900460ff1681565b60405190151581526020016101f0565b34801561051057600080fd5b506102b9611403565b34801561052557600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166102ea565b34801561055057600080fd5b506102b961055f3660046131f1565b611500565b6101e661057236600461326e565b61168b565b34801561058357600080fd5b506002546102ea9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105b057600080fd5b506102b9611b37565b3480156105c557600080fd5b506102b96105d43660046132e4565b611b92565b3480156105e557600080fd5b506002546104f4907501000000000000000000000000000000000000000000900460ff1681565b34801561061857600080fd5b506102b961062736600461333e565b612100565b34801561063857600080fd5b506005546006546003546002546040805194855263ffffffff808516602087015272010000000000000000000000000000000000008504811691860191909152760100000000000000000000000000000000000000000000808504821660608701526401000000008504821660808701526c01000000000000000000000000850490911660a086015261ffff70010000000000000000000000000000000085041660c086015260ff7a0100000000000000000000000000000000000000000000000000008504811660e08701527b0100000000000000000000000000000000000000000000000000000090940484166101008601526101208501929092520416610140820152610160016101f0565b34801561075357600080fd5b506006546107709068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101f0565b34801561079157600080fd5b506101e66107a0366004612e4d565b612179565b3480156107b157600080fd5b506102b96107c03660046131f1565b612297565b3480156107d157600080fd5b506101e660045481565b60025460009074010000000000000000000000000000000000000000900460ff16610867576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064015b60405180910390fd5b6002547501000000000000000000000000000000000000000000900460ff16156108ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b60006108f76122ab565b50905061090c8563ffffffff16858584612401565b95945050505050565b60025460009074010000000000000000000000000000000000000000900460ff1661099c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161085e565b6002547501000000000000000000000000000000000000000000900460ff1615610a22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b610a338363ffffffff16833a61255a565b90505b92915050565b8151600003610a805780610a7c576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b815160241115610ad15781516040517f51200dce00000000000000000000000000000000000000000000000000000000815261085e9160249160040161ffff92831681529116602082015260400190565b600082602381518110610ae657610ae6613359565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000149050808015610b3c5750815b15610b73576040517f6048aa6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015610b7f575081155b15610bb6576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610c2e576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116602482015260440161085e565b610bb6838383612668565b610c4161284e565b8163ffffffff168163ffffffff161115610c97576040517f2780dcb200000000000000000000000000000000000000000000000000000000815263ffffffff80831660048301528316602482015260440161085e565b609b60ff89161115610ce1576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff89166004820152609b602482015260440161085e565b609b60ff88161115610d2b576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff88166004820152609b602482015260440161085e565b8a600660046101000a81548163ffffffff021916908363ffffffff160217905550896006600c6101000a81548163ffffffff021916908363ffffffff16021790555088600660106101000a81548161ffff021916908361ffff160217905550876006601a6101000a81548160ff021916908360ff160217905550866006601b6101000a81548160ff021916908360ff1602179055508560038190555084600260166101000a81548160ff021916908360ff1602179055506001600260146101000a81548160ff02191690831515021790555083600660006101000a81548163ffffffff021916908363ffffffff1602179055508260058190555081600660126101000a81548163ffffffff021916908363ffffffff16021790555080600660166101000a81548163ffffffff021916908363ffffffff1602179055507fc79a05559cababbb44ef05174d6efe2c7107d46ba6691bf92263ee796aaf24568b8b8b8b8b8b8b8b8b8b600660169054906101000a900463ffffffff16604051610f1f9b9a9998979695949392919063ffffffff9b8c168152998b1660208b015261ffff9890981660408a015260ff96871660608a0152948616608089015260a0880193909352931660c086015291851660e085015261010084019190915283166101208301529091166101408201526101600190565b60405180910390a15050505050505050505050565b60025460009074010000000000000000000000000000000000000000900460ff16610fbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161085e565b6002547501000000000000000000000000000000000000000000900460ff1615611041576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b600061104b6122ab565b5090506110608463ffffffff16843a84612401565b949350505050565b61107061284e565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f75884cdadc4a89e8b545db800057f06ec7f5338a08183c7ba515f2bfdd9fe1e190600090a1565b6110e361284e565b604051479060009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d806000811461113d576040519150601f19603f3d011682016040523d82523d6000602084013e611142565b606091505b50509050806111ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e617469766500000000000000604482015260640161085e565b8273ffffffffffffffffffffffffffffffffffffffff167fc303ca808382409472acbbf899c316cf439f409f6584aae22df86dfa3c9ed504836040516111f591815260200190565b60405180910390a2505050565b61120a61284e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611297573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bb9190613388565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611355573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137991906133a1565b6113af576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040516113f791815260200190565b60405180910390a25050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161085e565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611540575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156115c4573361156560005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161085e565b73ffffffffffffffffffffffffffffffffffffffff8116611611576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be6906020015b60405180910390a150565b60025460009074010000000000000000000000000000000000000000900460ff16611712576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161085e565b6002547501000000000000000000000000000000000000000000900460ff1615611798576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b6117d783838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250610a3c915050565b60006117e2876128d1565b905060006117f78863ffffffff16873a61255a565b905080341015611863576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f77000000000000000000000000000000000000000000604482015260640161085e565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff871611156118f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f2068696768000000000000000000000000000000604482015260640161085e565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16858c61195691906133ed565b61196091906133ed565b63ffffffff1681526020018863ffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90611a06908490600401613411565b6020604051808303816000875af1158015611a25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a499190613388565b6040805160608101825233815263ffffffff808d16602080840191825267ffffffffffffffff3a81168587019081526000888152600790935295909120935184549251955190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9590931674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff91909116171792909216919091179055935050505095945050505050565b611b3f61284e565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517fc0f961051f97b04c496472d11cb6170d844e4b2c9dfd3b602a4fa0139712d48490600090a1565b60025474010000000000000000000000000000000000000000900460ff16611c16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161085e565b6002547501000000000000000000000000000000000000000000900460ff1615611c9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611d3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b000000000000000000604482015260640161085e565b6000808080611d4c8587018761346e565b9350935093509350611d5f816001610a3c565b6000611d6a856128d1565b9050600080611d776122ab565b915091506000611d8f8863ffffffff16873a86612401565b9050808b1015611dfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f77000000000000000000000000000000000000000000604482015260640161085e565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff87161115611e8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f2068696768000000000000000000000000000000604482015260640161085e565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16878c611eee91906133ed565b611ef891906133ed565b63ffffffff908116825289166020820152604090810188905260025490517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90611f6c908590600401613411565b6020604051808303816000875af1158015611f8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611faf9190613388565b905060405180606001604052808f73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020013a67ffffffffffffffff168152506007600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050508060048190555083156120f0576005546040805183815260208101929092527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b5050505050505050505050505050565b61210861284e565b600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff166801000000000000000063ffffffff8416908102919091179091556040519081527f697b48b8b76cebb09a54ec4ff810e8a181c96f65395d51c744db09c115d1d5d090602001611680565b60025460009074010000000000000000000000000000000000000000900460ff16612200576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161085e565b6002547501000000000000000000000000000000000000000000900460ff1615612286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161085e565b6110608463ffffffff16848461255a565b61229f61284e565b6122a8816128e9565b50565b6000806000600660009054906101000a900463ffffffff16905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612332573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235691906134f7565b50919650909250505063ffffffff82161580159061238257506123798142613547565b8263ffffffff16105b925082156123905760055493505b60008412156123fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b2077656920707269636500000000000000000000604482015260640161085e565b50509091565b600654600090819061242190640100000000900463ffffffff168561355a565b6006549091506000906124459068010000000000000000900463ffffffff166129de565b61244e87612aa6565b61245e9063ffffffff1689613571565b612468908761355a565b6124729190613571565b6006549091506000906124bd9063ffffffff76010000000000000000000000000000000000000000000082048116917201000000000000000000000000000000000000900416613584565b6124d29063ffffffff1664e8d4a5100061355a565b600654606490612504907b01000000000000000000000000000000000000000000000000000000900460ff16826135a1565b6125119060ff168561355a565b61251b91906135e9565b6125259190613571565b9050846125328285613571565b61254490670de0b6b3a764000061355a565b61254e91906135e9565b98975050505050505050565b600654600090819061257a90640100000000900463ffffffff168461355a565b60065490915060009061259e9068010000000000000000900463ffffffff166129de565b6125a786612aa6565b6125b79063ffffffff1688613571565b6125c1908661355a565b6125cb9190613571565b6006549091506000906125ff907201000000000000000000000000000000000000900463ffffffff1664e8d4a5100061355a565b600654606490612630907a010000000000000000000000000000000000000000000000000000900460ff16826135a1565b61263d9060ff168561355a565b61264791906135e9565b6126519190613571565b905061265d8184613571565b979650505050505050565b60008381526007602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835274010000000000000000000000000000000000000000820463ffffffff1683870152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff169382019390935288865293909252929055805190918116612763576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161085e565b600080631fe543e360e01b878787604051602401612783939291906135fd565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006127f9856020015163ffffffff168584612af1565b9050806128445760405173ffffffffffffffffffffffffffffffffffffffff85169089907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b5050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146128cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161085e565b565b60006128de603f83613656565b610a369060016133ed565b3373ffffffffffffffffffffffffffffffffffffffff821603612968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161085e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000466129ea81612b3d565b15612a7f576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015612a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a619190613679565b5050505091505083608c612a759190613571565b611060908261355a565b612a8881612b60565b15612a9d57612a9683612b9a565b9392505050565b50600092915050565b600654600090612ace90700100000000000000000000000000000000900461ffff16836136c3565b600654610a3691906c01000000000000000000000000900463ffffffff166133ed565b60005a611388811015612b0357600080fd5b611388810390508460408204820311612b1b57600080fd5b50823b612b2757600080fd5b60008083516020850160008789f1949350505050565b600061a4b1821480612b51575062066eed82145b80610a3657505062066eee1490565b6000600a821480612b7257506101a482145b80612b7f575062aa37dc82145b80612b8b575061210582145b80610a3657505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c209190613388565b9050600080612c2f8186613547565b90506000612c3e82601061355a565b612c4984600461355a565b612c539190613571565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cda9190613388565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d619190613388565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de89190613388565b90506000612df782600a61380b565b905060008184612e078789613571565b612e11908c61355a565b612e1b919061355a565b612e2591906135e9565b9b9a5050505050505050505050565b803563ffffffff81168114612e4857600080fd5b919050565b600080600060608486031215612e6257600080fd5b612e6b84612e34565b9250612e7960208501612e34565b9150604084013590509250925092565b60008060408385031215612e9c57600080fd5b612ea583612e34565b9150612eb360208401612e34565b90509250929050565b6000815180845260005b81811015612ee257602081850181015186830182015201612ec6565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610a336020830184612ebc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112612f7357600080fd5b813567ffffffffffffffff80821115612f8e57612f8e612f33565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612fd457612fd4612f33565b81604052838152866020858801011115612fed57600080fd5b836020870160208301376000602085830101528094505050505092915050565b80151581146122a857600080fd5b6000806040838503121561302e57600080fd5b823567ffffffffffffffff81111561304557600080fd5b61305185828601612f62565b92505060208301356130628161300d565b809150509250929050565b60008060006040848603121561308257600080fd5b83359250602084013567ffffffffffffffff808211156130a157600080fd5b818601915086601f8301126130b557600080fd5b8135818111156130c457600080fd5b8760208260051b85010111156130d957600080fd5b6020830194508093505050509250925092565b803561ffff81168114612e4857600080fd5b803560ff81168114612e4857600080fd5b60008060008060008060008060008060006101608c8e03121561313157600080fd5b61313a8c612e34565b9a5061314860208d01612e34565b995061315660408d016130ec565b985061316460608d016130fe565b975061317260808d016130fe565b965060a08c0135955061318760c08d016130fe565b945061319560e08d01612e34565b93506101008c013592506131ac6101208d01612e34565b91506131bb6101408d01612e34565b90509295989b509295989b9093969950565b803573ffffffffffffffffffffffffffffffffffffffff81168114612e4857600080fd5b60006020828403121561320357600080fd5b610a33826131cd565b60006020828403121561321e57600080fd5b5035919050565b60008083601f84011261323757600080fd5b50813567ffffffffffffffff81111561324f57600080fd5b60208301915083602082850101111561326757600080fd5b9250929050565b60008060008060006080868803121561328657600080fd5b61328f86612e34565b945061329d602087016130ec565b93506132ab60408701612e34565b9250606086013567ffffffffffffffff8111156132c757600080fd5b6132d388828901613225565b969995985093965092949392505050565b600080600080606085870312156132fa57600080fd5b613303856131cd565b935060208501359250604085013567ffffffffffffffff81111561332657600080fd5b61333287828801613225565b95989497509550505050565b60006020828403121561335057600080fd5b610a3382612e34565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561339a57600080fd5b5051919050565b6000602082840312156133b357600080fd5b8151612a968161300d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff81811683821601908082111561340a5761340a6133be565b5092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261106060e0840182612ebc565b6000806000806080858703121561348457600080fd5b61348d85612e34565b935061349b602086016130ec565b92506134a960408601612e34565b9150606085013567ffffffffffffffff8111156134c557600080fd5b6134d187828801612f62565b91505092959194509250565b805169ffffffffffffffffffff81168114612e4857600080fd5b600080600080600060a0868803121561350f57600080fd5b613518866134dd565b945060208601519350604086015192506060860151915061353b608087016134dd565b90509295509295909350565b81810381811115610a3657610a366133be565b8082028115828204841417610a3657610a366133be565b80820180821115610a3657610a366133be565b63ffffffff82811682821603908082111561340a5761340a6133be565b60ff8181168382160190811115610a3657610a366133be565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826135f8576135f86135ba565b500490565b8381526040602082015281604082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561363c57600080fd5b8260051b8085606085013791909101606001949350505050565b600063ffffffff8084168061366d5761366d6135ba565b92169190910492915050565b60008060008060008060c0878903121561369257600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b63ffffffff8181168382160280821691908281146136e3576136e36133be565b505092915050565b600181815b8085111561374457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561372a5761372a6133be565b8085161561373757918102915b93841c93908002906136f0565b509250929050565b60008261375b57506001610a36565b8161376857506000610a36565b816001811461377e5760028114613788576137a4565b6001915050610a36565b60ff841115613799576137996133be565b50506001821b610a36565b5060208310610133831016604e8410600b84101617156137c7575081810a610a36565b6137d183836136eb565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613803576138036133be565b029392505050565b6000610a33838361374c56fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedMinimumLength\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"actualLength\",\"type\":\"uint16\"}],\"name\":\"IncorrectExtraArgsLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LINKPaymentInRequestRandomWordsInNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativePaymentInOnTokenTransfer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIdMissing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverheadNative\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverheadLink\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Disabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Enabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"FulfillmentTxSizeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isLinkMode\",\"type\":\"bool\"}],\"name\":\"checkPaymentMode\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverheadNative\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverheadLink\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"wrapperNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"wrapperLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"link\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkNativeFeed\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"requestGasPrice\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverheadNative\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverheadLink\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_coordinatorGasOverheadPerWord\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"_stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"_fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60e06040526006805463ffffffff60401b191669024400000000000000001790553480156200002d57600080fd5b5060405162003e0938038062003e098339810160408190526200005091620002a1565b813380600081620000a85760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000db57620000db81620001d9565b5050506001600160a01b038116620001065760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392831617905584811660a052831660c0526000819003620001505760405163a81c0bef60e01b815260040160405180910390fd5b60025460405163dc311dd360e01b8152600481018390526001600160a01b039091169063dc311dd390602401600060405180830381865afa1580156200019a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001c4919081019062000321565b505050608092909252506200044a9350505050565b336001600160a01b03821603620002335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200029c57600080fd5b919050565b60008060008060808587031215620002b857600080fd5b620002c38562000284565b9350620002d36020860162000284565b9250620002e36040860162000284565b6060959095015193969295505050565b80516001600160601b03811681146200029c57600080fd5b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156200033a57600080fd5b6200034586620002f3565b9450602062000356818801620002f3565b60408801519095506001600160401b0380821682146200037557600080fd5b8195506200038660608a0162000284565b945060808901519150808211156200039d57600080fd5b818901915089601f830112620003b257600080fd5b815181811115620003c757620003c76200030b565b8060051b604051601f19603f83011681018181108582111715620003ef57620003ef6200030b565b60405291825284820192508381018501918c8311156200040e57600080fd5b938501935b828510156200043757620004278562000284565b8452938501939285019262000413565b8096505050505050509295509295909350565b60805160a05160c051613965620004a46000396000818161037e01526122840152600081816102ea015281816111f6015281816112c50152611c6f01526000818161020b015281816118c40152611e5c01526139656000f3fe6080604052600436106101c15760003560e01c806357a8070a116100f7578063a4c0ed3611610095578063cdd8d88511610064578063cdd8d88514610741578063e1cab7451461077f578063f2fde38b1461079f578063fc2a88c3146107bf57600080fd5b8063a4c0ed36146105b9578063a608a1e1146105d9578063bf17e5591461060c578063c3f909d41461062c57600080fd5b80638ea98117116100d15780638ea98117146105445780639cfc058e146105645780639eccacf614610577578063a3907d71146105a457600080fd5b806357a8070a146104c257806379ba5097146105045780638da5cb5b1461051957600080fd5b80631fe543e3116101645780632f2770db1161013e5780632f2770db146103a25780632f622e6b146103b757806348baa1c5146103d757806351cff8d9146104a257600080fd5b80631fe543e31461032f57806327e5c50a1461034f5780632808e6c81461036f57600080fd5b806313c34b7f116101a057806313c34b7f1461024f578063181f5a771461026f57806318b6f4c8146102bb5780631c4695f4146102db57600080fd5b806226501b146101c6578063030932bb146101f9578063045343aa1461022d575b600080fd5b3480156101d257600080fd5b506101e66101e1366004612e80565b6107d5565b6040519081526020015b60405180910390f35b34801561020557600080fd5b506101e67f000000000000000000000000000000000000000000000000000000000000000081565b34801561023957600080fd5b5061024d610248366004612edf565b61090f565b005b34801561025b57600080fd5b506101e661026a366004612fad565b610bcb565b34801561027b57600080fd5b50604080518082018252601681527f5652465632506c75735772617070657220312e302e3000000000000000000000602082015290516101f09190613044565b3480156102c757600080fd5b5061024d6102d636600461313f565b610cf2565b3480156102e757600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b34801561033b57600080fd5b5061024d61034a366004613191565b610e71565b34801561035b57600080fd5b506101e661036a366004612fad565b610eef565b34801561037b57600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061030a565b3480156103ae57600080fd5b5061024d611023565b3480156103c357600080fd5b5061024d6103d2366004613234565b611096565b3480156103e357600080fd5b506104616103f236600461324f565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810463ffffffff16907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1683565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff909216602084015267ffffffffffffffff16908201526060016101f0565b3480156104ae57600080fd5b5061024d6104bd366004613234565b6111bd565b3480156104ce57600080fd5b506002546104f49074010000000000000000000000000000000000000000900460ff1681565b60405190151581526020016101f0565b34801561051057600080fd5b5061024d6113be565b34801561052557600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661030a565b34801561055057600080fd5b5061024d61055f366004613234565b6114bb565b6101e66105723660046132b1565b611646565b34801561058357600080fd5b5060025461030a9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105b057600080fd5b5061024d611af2565b3480156105c557600080fd5b5061024d6105d4366004613327565b611b4d565b3480156105e557600080fd5b506002546104f4907501000000000000000000000000000000000000000000900460ff1681565b34801561061857600080fd5b5061024d610627366004613381565b6120bb565b34801561063857600080fd5b506005546006546003546002546040516101f0949363ffffffff808216947601000000000000000000000000000000000000000000008084048316957a010000000000000000000000000000000000000000000000000000850484169564010000000086048516956c0100000000000000000000000081048616957001000000000000000000000000000000008204169461ffff740100000000000000000000000000000000000000008304169460ff7e0100000000000000000000000000000000000000000000000000000000000084048116957f0100000000000000000000000000000000000000000000000000000000000000909404811694929391909104169061339c565b34801561074d57600080fd5b5060065461076a9068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101f0565b34801561078b57600080fd5b506101e661079a366004612e80565b612134565b3480156107ab57600080fd5b5061024d6107ba366004613234565b612252565b3480156107cb57600080fd5b506101e660045481565b60025460009074010000000000000000000000000000000000000000900460ff16610861576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064015b60405180910390fd5b6002547501000000000000000000000000000000000000000000900460ff16156108e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b60006108f1612266565b5090506109068563ffffffff168585846123bc565b95945050505050565b610917612523565b8163ffffffff168163ffffffff16111561096d576040517f2780dcb200000000000000000000000000000000000000000000000000000000815263ffffffff808316600483015283166024820152604401610858565b609b60ff891611156109b7576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff89166004820152609b6024820152604401610858565b609b60ff88161115610a01576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff88166004820152609b6024820152604401610858565b8b600660046101000a81548163ffffffff021916908363ffffffff1602179055508a6006600c6101000a81548163ffffffff021916908363ffffffff16021790555089600660106101000a81548163ffffffff021916908363ffffffff16021790555088600660146101000a81548161ffff021916908361ffff160217905550876006601e6101000a81548160ff021916908360ff160217905550866006601f6101000a81548160ff021916908360ff1602179055508560038190555084600260166101000a81548160ff021916908360ff1602179055506001600260146101000a81548160ff02191690831515021790555083600660006101000a81548163ffffffff021916908363ffffffff1602179055508260058190555081600660166101000a81548163ffffffff021916908363ffffffff160217905550806006601a6101000a81548163ffffffff021916908363ffffffff1602179055507f8aee1a8c131eaf1a5bd30594737b6926a7c5cb29281a97639f6ac93947c8995e8c8c8c8c8c8c8c8c8c8c8c6006601a9054906101000a900463ffffffff16604051610bb59c9b9a9998979695949392919061341d565b60405180910390a1505050505050505050505050565b60025460009074010000000000000000000000000000000000000000900460ff16610c52576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610858565b6002547501000000000000000000000000000000000000000000900460ff1615610cd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b610ce98363ffffffff16833a6125a6565b90505b92915050565b8151600003610d365780610d32576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b815160241115610d875781516040517f51200dce0000000000000000000000000000000000000000000000000000000081526108589160249160040161ffff92831681529116602082015260400190565b600082602381518110610d9c57610d9c61349a565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000149050808015610df25750815b15610e29576040517f6048aa6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015610e35575081155b15610e6c576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610ee4576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610858565b610e6c8383836126be565b60025460009074010000000000000000000000000000000000000000900460ff16610f76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610858565b6002547501000000000000000000000000000000000000000000900460ff1615610ffc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b6000611006612266565b50905061101b8463ffffffff16843a846123bc565b949350505050565b61102b612523565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f75884cdadc4a89e8b545db800057f06ec7f5338a08183c7ba515f2bfdd9fe1e190600090a1565b61109e612523565b604051479060009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d80600081146110f8576040519150601f19603f3d011682016040523d82523d6000602084013e6110fd565b606091505b5050905080611168576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e6174697665000000000000006044820152606401610858565b8273ffffffffffffffffffffffffffffffffffffffff167fc303ca808382409472acbbf899c316cf439f409f6584aae22df86dfa3c9ed504836040516111b091815260200190565b60405180910390a2505050565b6111c5612523565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611252573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127691906134c9565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611310573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133491906134e2565b61136a576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040516113b291815260200190565b60405180910390a25050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461143f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610858565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906114fb575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561157f573361152060005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610858565b73ffffffffffffffffffffffffffffffffffffffff81166115cc576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be6906020015b60405180910390a150565b60025460009074010000000000000000000000000000000000000000900460ff166116cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610858565b6002547501000000000000000000000000000000000000000000900460ff1615611753576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b61179283838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250610cf2915050565b600061179d876128a4565b905060006117b28863ffffffff16873a6125a6565b90508034101561181e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610858565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff871611156118ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610858565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16858c611911919061352e565b61191b919061352e565b63ffffffff1681526020018863ffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906119c1908490600401613552565b6020604051808303816000875af11580156119e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0491906134c9565b6040805160608101825233815263ffffffff808d16602080840191825267ffffffffffffffff3a81168587019081526000888152600790935295909120935184549251955190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9590931674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff91909116171792909216919091179055935050505095945050505050565b611afa612523565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517fc0f961051f97b04c496472d11cb6170d844e4b2c9dfd3b602a4fa0139712d48490600090a1565b60025474010000000000000000000000000000000000000000900460ff16611bd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610858565b6002547501000000000000000000000000000000000000000000900460ff1615611c57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611cf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b0000000000000000006044820152606401610858565b6000808080611d07858701876135af565b9350935093509350611d1a816001610cf2565b6000611d25856128a4565b9050600080611d32612266565b915091506000611d4a8863ffffffff16873a866123bc565b9050808b1015611db6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610858565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff87161115611e45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610858565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16878c611ea9919061352e565b611eb3919061352e565b63ffffffff908116825289166020820152604090810188905260025490517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90611f27908590600401613552565b6020604051808303816000875af1158015611f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6a91906134c9565b905060405180606001604052808f73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020013a67ffffffffffffffff168152506007600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050508060048190555083156120ab576005546040805183815260208101929092527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b5050505050505050505050505050565b6120c3612523565b600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff166801000000000000000063ffffffff8416908102919091179091556040519081527f697b48b8b76cebb09a54ec4ff810e8a181c96f65395d51c744db09c115d1d5d09060200161163b565b60025460009074010000000000000000000000000000000000000000900460ff166121bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610858565b6002547501000000000000000000000000000000000000000000900460ff1615612241576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610858565b61101b8463ffffffff1684846125a6565b61225a612523565b612263816128bc565b50565b6000806000600660009054906101000a900463ffffffff16905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156122ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123119190613638565b50919650909250505063ffffffff82161580159061233d57506123348142613688565b8263ffffffff16105b9250821561234b5760055493505b60008412156123b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b20776569207072696365000000000000000000006044820152606401610858565b50509091565b60065460009081906123dc90640100000000900463ffffffff168561369b565b6006549091506000906124009068010000000000000000900463ffffffff166129b1565b61240b876000612a79565b61241b9063ffffffff16896136b2565b612425908761369b565b61242f91906136b2565b6006549091506000906124829063ffffffff7a01000000000000000000000000000000000000000000000000000082048116917601000000000000000000000000000000000000000000009004166136c5565b6124979063ffffffff1664e8d4a5100061369b565b6006546064906124cd907f0100000000000000000000000000000000000000000000000000000000000000900460ff16826136e2565b6124da9060ff168561369b565b6124e4919061372a565b6124ee91906136b2565b9050846124fb82856136b2565b61250d90670de0b6b3a764000061369b565b612517919061372a565b98975050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146125a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610858565b565b60065460009081906125c690640100000000900463ffffffff168461369b565b6006549091506000906125ea9068010000000000000000900463ffffffff166129b1565b6125f5866001612a79565b6126059063ffffffff16886136b2565b61260f908661369b565b61261991906136b2565b60065490915060009061265190760100000000000000000000000000000000000000000000900463ffffffff1664e8d4a5100061369b565b600654606490612686907e01000000000000000000000000000000000000000000000000000000000000900460ff16826136e2565b6126939060ff168561369b565b61269d919061372a565b6126a791906136b2565b90506126b381846136b2565b979650505050505050565b60008381526007602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835274010000000000000000000000000000000000000000820463ffffffff1683870152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1693820193909352888652939092529290558051909181166127b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610858565b600080631fe543e360e01b8787876040516024016127d99392919061373e565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600061284f856020015163ffffffff168584612b24565b90508061289a5760405173ffffffffffffffffffffffffffffffffffffffff85169089907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b5050505050505050565b60006128b1603f83613797565b610cec90600161352e565b3373ffffffffffffffffffffffffffffffffffffffff82160361293b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610858565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000466129bd81612b70565b15612a52576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015612a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a3491906137ba565b5050505091505083608c612a4891906136b2565b61101b908261369b565b612a5b81612b93565b15612a7057612a6983612bcd565b9392505050565b50600092915050565b60008115612ad457600654612aaa9074010000000000000000000000000000000000000000900461ffff1684613804565b600654612acd91906c01000000000000000000000000900463ffffffff1661352e565b9050610cec565b600654612afd9074010000000000000000000000000000000000000000900461ffff1684613804565b600654612acd9190700100000000000000000000000000000000900463ffffffff1661352e565b60005a611388811015612b3657600080fd5b611388810390508460408204820311612b4e57600080fd5b50823b612b5a57600080fd5b60008083516020850160008789f1949350505050565b600061a4b1821480612b84575062066eed82145b80610cec57505062066eee1490565b6000600a821480612ba557506101a482145b80612bb2575062aa37dc82145b80612bbe575061210582145b80610cec57505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5391906134c9565b9050600080612c628186613688565b90506000612c7182601061369b565b612c7c84600461369b565b612c8691906136b2565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0d91906134c9565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9491906134c9565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612df7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1b91906134c9565b90506000612e2a82600a61394c565b905060008184612e3a87896136b2565b612e44908c61369b565b612e4e919061369b565b612e58919061372a565b9b9a5050505050505050505050565b803563ffffffff81168114612e7b57600080fd5b919050565b600080600060608486031215612e9557600080fd5b612e9e84612e67565b9250612eac60208501612e67565b9150604084013590509250925092565b803561ffff81168114612e7b57600080fd5b803560ff81168114612e7b57600080fd5b6000806000806000806000806000806000806101808d8f031215612f0257600080fd5b612f0b8d612e67565b9b50612f1960208e01612e67565b9a50612f2760408e01612e67565b9950612f3560608e01612ebc565b9850612f4360808e01612ece565b9750612f5160a08e01612ece565b965060c08d01359550612f6660e08e01612ece565b9450612f756101008e01612e67565b93506101208d01359250612f8c6101408e01612e67565b9150612f9b6101608e01612e67565b90509295989b509295989b509295989b565b60008060408385031215612fc057600080fd5b612fc983612e67565b9150612fd760208401612e67565b90509250929050565b6000815180845260005b8181101561300657602081850181015186830182015201612fea565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610ce96020830184612fe0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261309757600080fd5b813567ffffffffffffffff808211156130b2576130b2613057565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156130f8576130f8613057565b8160405283815286602085880101111561311157600080fd5b836020870160208301376000602085830101528094505050505092915050565b801515811461226357600080fd5b6000806040838503121561315257600080fd5b823567ffffffffffffffff81111561316957600080fd5b61317585828601613086565b925050602083013561318681613131565b809150509250929050565b6000806000604084860312156131a657600080fd5b83359250602084013567ffffffffffffffff808211156131c557600080fd5b818601915086601f8301126131d957600080fd5b8135818111156131e857600080fd5b8760208260051b85010111156131fd57600080fd5b6020830194508093505050509250925092565b803573ffffffffffffffffffffffffffffffffffffffff81168114612e7b57600080fd5b60006020828403121561324657600080fd5b610ce982613210565b60006020828403121561326157600080fd5b5035919050565b60008083601f84011261327a57600080fd5b50813567ffffffffffffffff81111561329257600080fd5b6020830191508360208285010111156132aa57600080fd5b9250929050565b6000806000806000608086880312156132c957600080fd5b6132d286612e67565b94506132e060208701612ebc565b93506132ee60408701612e67565b9250606086013567ffffffffffffffff81111561330a57600080fd5b61331688828901613268565b969995985093965092949392505050565b6000806000806060858703121561333d57600080fd5b61334685613210565b935060208501359250604085013567ffffffffffffffff81111561336957600080fd5b61337587828801613268565b95989497509550505050565b60006020828403121561339357600080fd5b610ce982612e67565b8c815263ffffffff8c811660208301528b811660408301528a81166060830152898116608083015288811660a0830152871660c082015261ffff861660e082015260ff858116610100830152841661012082015261018081018361014083015261340c61016083018460ff169052565b9d9c50505050505050505050505050565b63ffffffff8d811682528c811660208301528b8116604083015261ffff8b16606083015260ff8a8116608084015289811660a084015260c08301899052871660e0830152851661010082015261018081018461012083015261348861014083018563ffffffff169052565b63ffffffff831661016083015261340c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156134db57600080fd5b5051919050565b6000602082840312156134f457600080fd5b8151612a6981613131565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff81811683821601908082111561354b5761354b6134ff565b5092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261101b60e0840182612fe0565b600080600080608085870312156135c557600080fd5b6135ce85612e67565b93506135dc60208601612ebc565b92506135ea60408601612e67565b9150606085013567ffffffffffffffff81111561360657600080fd5b61361287828801613086565b91505092959194509250565b805169ffffffffffffffffffff81168114612e7b57600080fd5b600080600080600060a0868803121561365057600080fd5b6136598661361e565b945060208601519350604086015192506060860151915061367c6080870161361e565b90509295509295909350565b81810381811115610cec57610cec6134ff565b8082028115828204841417610cec57610cec6134ff565b80820180821115610cec57610cec6134ff565b63ffffffff82811682821603908082111561354b5761354b6134ff565b60ff8181168382160190811115610cec57610cec6134ff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613739576137396136fb565b500490565b8381526040602082015281604082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561377d57600080fd5b8260051b8085606085013791909101606001949350505050565b600063ffffffff808416806137ae576137ae6136fb565b92169190910492915050565b60008060008060008060c087890312156137d357600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b63ffffffff818116838216028082169190828114613824576138246134ff565b505092915050565b600181815b8085111561388557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561386b5761386b6134ff565b8085161561387857918102915b93841c9390800290613831565b509250929050565b60008261389c57506001610cec565b816138a957506000610cec565b81600181146138bf57600281146138c9576138e5565b6001915050610cec565b60ff8411156138da576138da6134ff565b50506001821b610cec565b5060208310610133831016604e8410600b8410161715613908575081810a610cec565b613912838361382c565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613944576139446134ff565b029392505050565b6000610ce9838361388d56fea164736f6c6343000813000a", } var VRFV2PlusWrapperABI = VRFV2PlusWrapperMetaData.ABI @@ -317,12 +317,13 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) GetConfig(opts *bind.CallOpts) outstruct.FulfillmentFlatFeeNativePPM = *abi.ConvertType(out[2], new(uint32)).(*uint32) outstruct.FulfillmentFlatFeeLinkDiscountPPM = *abi.ConvertType(out[3], new(uint32)).(*uint32) outstruct.WrapperGasOverhead = *abi.ConvertType(out[4], new(uint32)).(*uint32) - outstruct.CoordinatorGasOverhead = *abi.ConvertType(out[5], new(uint32)).(*uint32) - outstruct.CoordinatorGasOverheadPerWord = *abi.ConvertType(out[6], new(uint16)).(*uint16) - outstruct.WrapperNativePremiumPercentage = *abi.ConvertType(out[7], new(uint8)).(*uint8) - outstruct.WrapperLinkPremiumPercentage = *abi.ConvertType(out[8], new(uint8)).(*uint8) - outstruct.KeyHash = *abi.ConvertType(out[9], new([32]byte)).(*[32]byte) - outstruct.MaxNumWords = *abi.ConvertType(out[10], new(uint8)).(*uint8) + outstruct.CoordinatorGasOverheadNative = *abi.ConvertType(out[5], new(uint32)).(*uint32) + outstruct.CoordinatorGasOverheadLink = *abi.ConvertType(out[6], new(uint32)).(*uint32) + outstruct.CoordinatorGasOverheadPerWord = *abi.ConvertType(out[7], new(uint16)).(*uint16) + outstruct.WrapperNativePremiumPercentage = *abi.ConvertType(out[8], new(uint8)).(*uint8) + outstruct.WrapperLinkPremiumPercentage = *abi.ConvertType(out[9], new(uint8)).(*uint8) + outstruct.KeyHash = *abi.ConvertType(out[10], new([32]byte)).(*[32]byte) + outstruct.MaxNumWords = *abi.ConvertType(out[11], new(uint8)).(*uint8) return *outstruct, err @@ -641,16 +642,16 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) RequestRandomWordsIn return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, extraArgs) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverheadNative uint32, _coordinatorGasOverheadLink uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverheadNative, _coordinatorGasOverheadLink, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverheadNative uint32, _coordinatorGasOverheadLink uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverheadNative, _coordinatorGasOverheadLink, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverheadNative uint32, _coordinatorGasOverheadLink uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverheadNative, _coordinatorGasOverheadLink, _coordinatorGasOverheadPerWord, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) { @@ -775,7 +776,8 @@ func (it *VRFV2PlusWrapperConfigSetIterator) Close() error { type VRFV2PlusWrapperConfigSet struct { WrapperGasOverhead uint32 - CoordinatorGasOverhead uint32 + CoordinatorGasOverheadNative uint32 + CoordinatorGasOverheadLink uint32 CoordinatorGasOverheadPerWord uint16 CoordinatorNativePremiumPercentage uint8 CoordinatorLinkPremiumPercentage uint8 @@ -2094,7 +2096,8 @@ type GetConfig struct { FulfillmentFlatFeeNativePPM uint32 FulfillmentFlatFeeLinkDiscountPPM uint32 WrapperGasOverhead uint32 - CoordinatorGasOverhead uint32 + CoordinatorGasOverheadNative uint32 + CoordinatorGasOverheadLink uint32 CoordinatorGasOverheadPerWord uint16 WrapperNativePremiumPercentage uint8 WrapperLinkPremiumPercentage uint8 @@ -2138,7 +2141,7 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapper) ParseLog(log types.Log) (generated.Ab } func (VRFV2PlusWrapperConfigSet) Topic() common.Hash { - return common.HexToHash("0xc79a05559cababbb44ef05174d6efe2c7107d46ba6691bf92263ee796aaf2456") + return common.HexToHash("0x8aee1a8c131eaf1a5bd30594737b6926a7c5cb29281a97639f6ac93947c8995e") } func (VRFV2PlusWrapperCoordinatorSet) Topic() common.Hash { @@ -2236,7 +2239,7 @@ type VRFV2PlusWrapperInterface interface { RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) - SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) + SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverheadNative uint32, _coordinatorGasOverheadLink uint32, _coordinatorGasOverheadPerWord uint16, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 4cee5f8be1c..54925200f81 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -8,13 +8,13 @@ automation_compatible_utils: ../../contracts/solc/v0.8.19/AutomationCompatibleUt automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 -automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.bin f07ffea17d8d7c2bd5ea91c25a32e2fa64aa6bffbd81a3281ebdb9b542535202 +automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.bin b42de91c15c7453d8262124e20594819d64a3f23bef8e6db66fa5180d18a8454 automation_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 2f267fb8467a15c587ce4586ac56069f7229344ad3936430d7c7624c0528a171 -automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 918082df412d3138c727871545fbcff7d9c9724e56990f8e5e0ab93809f83364 +automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 1163ecd34c575cb17ffbc2f88fa175816f36982e91992d940ed435d306b3418c automation_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin a6d33dfbbfb0ff253eb59a51f4f6d6d4c22ea5ec95aae52d25d49a312b37a22f -automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin b811c11616795e82e416cb8deff85b4d90b9c15f0aea23a5ea35a0d61c37dffc +automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin 2d0f45d2087f6f3c8bfa0a16b26a1c8c1d5c64b89859478c609201535c96eeed automation_registry_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.bin de60f69878e9b32a291a001c91fc8636544c2cfbd9b507c8c1a4873b602bfb62 -automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 9aaed50d72437f3882b64f69018606d97f13f9b7c4e4b82ad0da66f2694be433 +automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 2f9db5da86183eaf4f78f726458e5a928d37f7c90c4024923847b25186b644c5 automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 815b17b63f15d26a0274b962eefad98cdee4ec897ead58688bbb8e2470e585f5 automation_utils_2_2: ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.bin 8743f6231aaefa3f2a0b2d484258070d506e2d0860690e66890dccc3949edb2e automation_utils_2_3: ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin 11e2b481dc9a4d936e3443345d45d2cc571164459d214917b42a8054b295393b @@ -31,7 +31,7 @@ dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 i_automation_registry_master_wrapper_2_2: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.bin 9ff7087179f89f9b05964ebc3e71332fce11f1b8e85058f7b16b3bc0dd6fb96b -i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin 16b346a64126554bad0929f49ce020d886cc7203d03ca52c4537daf273b4c369 +i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin fbfa3f5d78a357ecb7a1bc597c629ff30d42fedc48ba7f57e1622a6302d36523 i_automation_v21_plus_common: ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.abi ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.bin e8a601ec382c0a2e83c49759de13b0622b5e04e6b95901e96a1e9504329e594c i_chain_module: ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin 383611981c86c70522f41b8750719faacc7d7933a22849d5004799ebef3371fa i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin ee0f150b3afbab2df3d24ff3f4c87851efa635da30db04cd1f70cb4e185a1781 @@ -99,7 +99,7 @@ vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin 593dbcdcc212fc9ec69fe71684711d112433cc31218fe21305ace9229ac29289 vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin cfdfb97b1b0801ee778410d54b1f6541395ac01ab592ffd6c3feaf4a3ac3eca2 vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin 6032a081ad15453e52af1cf37c74a9f77f2a30bc14b2cb35f564eabc4b0b4c2e -vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin 4a7df5b066bc3944622009659828fae35bc39d15cf4d218c1560dbdf39b10de2 +vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin 50429c68bc9e4edcddc4b15d65867bff9ae308314b52ed997e7d5665f0703148 vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin 402b1103087ffe1aa598854a8f8b38f8cd3de2e3aaa86369e28017a9157f4980 vrfv2_reverting_example: ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.bin 1ae46f80351d428bd85ba58b9041b2a608a1845300d79a8fed83edf96606de87 vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin fe1a8e6852fbd06d91f64315c5cede86d340891f5b5cc981fb5b86563f7eac3f @@ -111,6 +111,6 @@ vrfv2plus_client: ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.a vrfv2plus_consumer_example: ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin 5e0bdf21048dd6b405ccaa3d260d7fb6d24fd256094310a5cb149aed68e4f892 vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 5dff20621fe6ed3bed75fe4b65381b0d4b1f6286ee3571553dbeb57213b53416 vrfv2plus_reverting_example: ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin 82860e6ed846eaa4a5127b96c8ce4e444138412e9ed0605cfdecb6995436b3af -vrfv2plus_wrapper: ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.bin 9d601662c578e5da232f065bde0053a6a03545127e8cac6f8897a78bc0861b3f +vrfv2plus_wrapper: ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.bin 3c98547449e5ce5ba7a858efa48052407247771c4f6f59f883a9ba38018ef634 vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin 7554bc93b2a60361cdd5611f7802de58deba6257a84d11545993f4aa37bdff02 vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin 824cf74f968382efdcbbbc866eef884c13d59295b1f07b6646727ed4c0686c86 diff --git a/core/gethwrappers/go_generate_test.go b/core/gethwrappers/go_generate_test.go index 52d0f520dd7..a6253cb1a66 100644 --- a/core/gethwrappers/go_generate_test.go +++ b/core/gethwrappers/go_generate_test.go @@ -4,6 +4,7 @@ package gethwrappers import ( "crypto/sha256" + "flag" "fmt" "os" "os/exec" @@ -15,6 +16,7 @@ import ( "github.com/fatih/color" cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" @@ -27,6 +29,7 @@ const compileCommand = "../../contracts/scripts/native_solc_compile_all" // contract artifacts in contracts/solc with the abi and bytecode stored in the // contract wrapper func TestCheckContractHashesFromLastGoGenerate(t *testing.T) { + testutils.SkipShort(t, "requires compiled artifacts") versions, err := ReadVersionsDB() require.NoError(t, err) require.NotEmpty(t, versions.GethVersion, `version DB should have a "GETH_VERSION:" line`) @@ -63,19 +66,13 @@ func isVRFV2Contract(fullpath string) bool { return strings.Contains(fullpath, "VRFCoordinatorV2") } -// rootDir is the local chainlink root working directory -var rootDir string - -func init() { // compute rootDir - var err error - thisDir, err := os.Getwd() - if err != nil { - panic(err) - } - rootDir, err = filepath.Abs(filepath.Join(thisDir, "../..")) +// getRootDir returns the local chainlink root working directory +func getRootDir() (string, error) { // compute rootDir + wd, err := os.Getwd() if err != nil { - panic(err) + return "", fmt.Errorf("failed to get working directory: %w", err) } + return filepath.Abs(filepath.Join(wd, "../..")) } // compareCurrentCompilerArtifactAgainstRecordsAndSoliditySources checks that @@ -95,6 +92,8 @@ func compareCurrentCompilerArtifactAgainstRecordsAndSoliditySources( t *testing.T, versionInfo ContractVersion, ) { hash := VersionHash(versionInfo.AbiPath, versionInfo.BinaryPath) + rootDir, err := getRootDir() + require.NoError(t, err) recompileCommand := fmt.Sprintf("(cd %s/contracts; make wrappers-all)", rootDir) assert.Equal(t, versionInfo.Hash, hash, utils.BoxOutput(`compiled %s and/or %s has changed; please rerun @@ -102,9 +101,17 @@ func compareCurrentCompilerArtifactAgainstRecordsAndSoliditySources( and commit the changes`, versionInfo.AbiPath, versionInfo.BinaryPath, recompileCommand)) } +func TestMain(m *testing.M) { + flag.Parse() + if !testing.Short() { + ensureArtifacts() + } + os.Exit(m.Run()) +} + // Ensure that solidity compiler artifacts are present before running this test, // by compiling them if necessary. -func init() { +func ensureArtifacts() { db, err := versionsDBLineReader() if err != nil { panic(err) diff --git a/core/gethwrappers/keystone/generated/forwarder/forwarder.go b/core/gethwrappers/keystone/generated/forwarder/forwarder.go index c66e2886793..c8cf31ae869 100644 --- a/core/gethwrappers/keystone/generated/forwarder/forwarder.go +++ b/core/gethwrappers/keystone/generated/forwarder/forwarder.go @@ -31,8 +31,8 @@ var ( ) var KeystoneForwarderMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"}],\"name\":\"getTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"targetAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"report\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b610c12806101576000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063c0965dc311610050578063c0965dc314610108578063e6b714581461012b578063f2fde38b1461016157600080fd5b8063181f5a771461007757806379ba5097146100bf5780638da5cb5b146100c9575b600080fd5b604080518082018252601781527f4b657973746f6e65466f7277617264657220312e302e30000000000000000000602082015290516100b69190610827565b60405180910390f35b6100c7610174565b005b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b6565b61011b6101163660046108bc565b610276565b60405190151581526020016100b6565b6100e3610139366004610998565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6100c761016f3660046109b1565b61058e565b60015473ffffffffffffffffffffffffffffffffffffffff1633146101fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60025460009060ff16156102b6576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556044841161034b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c69642064617461206c656e6774680000000000000000000000000060448201526064016101f1565b600061035a85600481896109d3565b8101906103679190610a2c565b8051602082012090915060005b848110156104655760008060006103e289898681811061039657610396610afb565b90506020028101906103a89190610b2a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506105a292505050565b925092509250600060018683868660405160008152602001604052604051610426949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610448573d6000803e3d6000fd5b5086955061045d9450859350610b9692505050565b915050610374565b5060008061047284610630565b600081815260036020526040902054919350915073ffffffffffffffffffffffffffffffffffffffff16156104ae57600094505050505061055d565b6000808b73ffffffffffffffffffffffffffffffffffffffff168b8b6040516104d8929190610bf5565b6000604051808303816000865af19150503d8060008114610515576040519150601f19603f3d011682016040523d82523d6000602084013e61051a565b606091505b5050506000928352505060036020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055506001925050505b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905595945050505050565b6105966106af565b61059f81610732565b50565b60008060008351604114610612576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e677468000000000000000060448201526064016101f1565b50505060208101516040820151606090920151909260009190911a90565b600080604083511161069e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207265706f7274206c656e677468000000000000000000000060448201526064016101f1565b505060208101516040909101519091565b60005473ffffffffffffffffffffffffffffffffffffffff163314610730576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101f1565b565b3373ffffffffffffffffffffffffffffffffffffffff8216036107b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208083528351808285015260005b8181101561085457858101830151858201604001528201610838565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108b757600080fd5b919050565b6000806000806000606086880312156108d457600080fd5b6108dd86610893565b9450602086013567ffffffffffffffff808211156108fa57600080fd5b818801915088601f83011261090e57600080fd5b81358181111561091d57600080fd5b89602082850101111561092f57600080fd5b60208301965080955050604088013591508082111561094d57600080fd5b818801915088601f83011261096157600080fd5b81358181111561097057600080fd5b8960208260051b850101111561098557600080fd5b9699959850939650602001949392505050565b6000602082840312156109aa57600080fd5b5035919050565b6000602082840312156109c357600080fd5b6109cc82610893565b9392505050565b600080858511156109e357600080fd5b838611156109f057600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610a3e57600080fd5b813567ffffffffffffffff80821115610a5657600080fd5b818401915084601f830112610a6a57600080fd5b813581811115610a7c57610a7c6109fd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610ac257610ac26109fd565b81604052828152876020848701011115610adb57600080fd5b826020860160208301376000928101602001929092525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b5f57600080fd5b83018035915067ffffffffffffffff821115610b7a57600080fd5b602001915036819003821315610b8f57600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610bee577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b818382376000910190815291905056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"InvalidData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"}],\"name\":\"getTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"targetAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"report\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b610c5f806101576000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063c0965dc311610050578063c0965dc314610108578063e6b714581461012b578063f2fde38b1461016157600080fd5b8063181f5a771461007757806379ba5097146100bf5780638da5cb5b146100c9575b600080fd5b604080518082018252601781527f4b657973746f6e65466f7277617264657220312e302e30000000000000000000602082015290516100b69190610806565b60405180910390f35b6100c7610174565b005b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b6565b61011b61011636600461089b565b610276565b60405190151581526020016100b6565b6100e3610139366004610977565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6100c761016f366004610990565b61056d565b60015473ffffffffffffffffffffffffffffffffffffffff1633146101fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60025460009060ff16156102b6576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556102ed604060046109e1565b84101561032a5784846040517f2a62609b0000000000000000000000000000000000000000000000000000000081526004016101f19291906109fa565b60006103398560048189610a47565b8101906103469190610aa0565b8051602082012090915060005b848110156104445760008060006103c189898681811061037557610375610b6f565b90506020028101906103879190610b9e565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061058192505050565b925092509250600060018683868660405160008152602001604052604051610405949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610427573d6000803e3d6000fd5b5086955061043c9450859350610c0a92505050565b915050610353565b506000806104518461060f565b600081815260036020526040902054919350915073ffffffffffffffffffffffffffffffffffffffff161561048d57600094505050505061053c565b6000808b73ffffffffffffffffffffffffffffffffffffffff168b8b6040516104b7929190610c42565b6000604051808303816000865af19150503d80600081146104f4576040519150601f19603f3d011682016040523d82523d6000602084013e6104f9565b606091505b5050506000928352505060036020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055506001925050505b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905595945050505050565b61057561068e565b61057e81610711565b50565b600080600083516041146105f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964207369676e6174757265206c656e677468000000000000000060448201526064016101f1565b50505060208101516040820151606090920151909260009190911a90565b600080604083511161067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207265706f7274206c656e677468000000000000000000000060448201526064016101f1565b505060208101516040909101519091565b60005473ffffffffffffffffffffffffffffffffffffffff16331461070f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101f1565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610790576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208083528351808285015260005b8181101561083357858101830151858201604001528201610817565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461089657600080fd5b919050565b6000806000806000606086880312156108b357600080fd5b6108bc86610872565b9450602086013567ffffffffffffffff808211156108d957600080fd5b818801915088601f8301126108ed57600080fd5b8135818111156108fc57600080fd5b89602082850101111561090e57600080fd5b60208301965080955050604088013591508082111561092c57600080fd5b818801915088601f83011261094057600080fd5b81358181111561094f57600080fd5b8960208260051b850101111561096457600080fd5b9699959850939650602001949392505050565b60006020828403121561098957600080fd5b5035919050565b6000602082840312156109a257600080fd5b6109ab82610872565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156109f4576109f46109b2565b92915050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60008085851115610a5757600080fd5b83861115610a6457600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610ab257600080fd5b813567ffffffffffffffff80821115610aca57600080fd5b818401915084601f830112610ade57600080fd5b813581811115610af057610af0610a71565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610b3657610b36610a71565b81604052828152876020848701011115610b4f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610bd357600080fd5b83018035915067ffffffffffffffff821115610bee57600080fd5b602001915036819003821315610c0357600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c3b57610c3b6109b2565b5060010190565b818382376000910190815291905056fea164736f6c6343000813000a", } var KeystoneForwarderABI = KeystoneForwarderMetaData.ABI diff --git a/core/gethwrappers/keystone/generated/keystone_capability_registry/keystone_capability_registry.go b/core/gethwrappers/keystone/generated/keystone_capability_registry/keystone_capability_registry.go new file mode 100644 index 00000000000..45ae103ac56 --- /dev/null +++ b/core/gethwrappers/keystone/generated/keystone_capability_registry/keystone_capability_registry.go @@ -0,0 +1,768 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keystone_capability_registry + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type Capability struct { + CapabilityType [32]byte + Version [32]byte +} + +var CapabilityRegistryMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityType\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"}],\"internalType\":\"structCapability\",\"name\":\"capability\",\"type\":\"tuple\"}],\"name\":\"addCapability\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityID\",\"type\":\"bytes32\"}],\"name\":\"getCapability\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityType\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"}],\"internalType\":\"structCapability\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityType\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"}],\"name\":\"getCapabilityID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6105e5806101576000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806379ba50971161005b57806379ba5097146101275780638da5cb5b1461012f5780639cb7c5f414610157578063f2fde38b146101be57600080fd5b8063181f5a7714610082578063229111f5146100ca5780636e5f286914610112575b600080fd5b604080518082018252601881527f4361706162696c697479526567697374727920312e302e300000000000000000602082015290516100c191906104dc565b60405180910390f35b6101046100d8366004610548565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b6040519081526020016100c1565b61012561012036600461056a565b6101d1565b005b61012561024e565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c1565b6101a3610165366004610582565b604080518082019091526000808252602082015250600090815260026020908152604091829020825180840190935280548352600101549082015290565b604080518251815260209283015192810192909252016100c1565b6101256101cc36600461059b565b610350565b6101d9610364565b60408051823560208083018290528085013583850181905284518085038601815260609094018086528451948301949094206000818152600290935294822092835560019092019190915582917f65610e5677eedff94555572640e442f89848a109ef8593fa927ac30b2565ff069190a25050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610358610364565b610361816103e7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102cb565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610466576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102cb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208083528351808285015260005b81811015610509578581018301518582016040015282016104ed565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6000806040838503121561055b57600080fd5b50508035926020909101359150565b60006040828403121561057c57600080fd5b50919050565b60006020828403121561059457600080fd5b5035919050565b6000602082840312156105ad57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146105d157600080fd5b939250505056fea164736f6c6343000813000a", +} + +var CapabilityRegistryABI = CapabilityRegistryMetaData.ABI + +var CapabilityRegistryBin = CapabilityRegistryMetaData.Bin + +func DeployCapabilityRegistry(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *CapabilityRegistry, error) { + parsed, err := CapabilityRegistryMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CapabilityRegistryBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &CapabilityRegistry{address: address, abi: *parsed, CapabilityRegistryCaller: CapabilityRegistryCaller{contract: contract}, CapabilityRegistryTransactor: CapabilityRegistryTransactor{contract: contract}, CapabilityRegistryFilterer: CapabilityRegistryFilterer{contract: contract}}, nil +} + +type CapabilityRegistry struct { + address common.Address + abi abi.ABI + CapabilityRegistryCaller + CapabilityRegistryTransactor + CapabilityRegistryFilterer +} + +type CapabilityRegistryCaller struct { + contract *bind.BoundContract +} + +type CapabilityRegistryTransactor struct { + contract *bind.BoundContract +} + +type CapabilityRegistryFilterer struct { + contract *bind.BoundContract +} + +type CapabilityRegistrySession struct { + Contract *CapabilityRegistry + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type CapabilityRegistryCallerSession struct { + Contract *CapabilityRegistryCaller + CallOpts bind.CallOpts +} + +type CapabilityRegistryTransactorSession struct { + Contract *CapabilityRegistryTransactor + TransactOpts bind.TransactOpts +} + +type CapabilityRegistryRaw struct { + Contract *CapabilityRegistry +} + +type CapabilityRegistryCallerRaw struct { + Contract *CapabilityRegistryCaller +} + +type CapabilityRegistryTransactorRaw struct { + Contract *CapabilityRegistryTransactor +} + +func NewCapabilityRegistry(address common.Address, backend bind.ContractBackend) (*CapabilityRegistry, error) { + abi, err := abi.JSON(strings.NewReader(CapabilityRegistryABI)) + if err != nil { + return nil, err + } + contract, err := bindCapabilityRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &CapabilityRegistry{address: address, abi: abi, CapabilityRegistryCaller: CapabilityRegistryCaller{contract: contract}, CapabilityRegistryTransactor: CapabilityRegistryTransactor{contract: contract}, CapabilityRegistryFilterer: CapabilityRegistryFilterer{contract: contract}}, nil +} + +func NewCapabilityRegistryCaller(address common.Address, caller bind.ContractCaller) (*CapabilityRegistryCaller, error) { + contract, err := bindCapabilityRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &CapabilityRegistryCaller{contract: contract}, nil +} + +func NewCapabilityRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*CapabilityRegistryTransactor, error) { + contract, err := bindCapabilityRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &CapabilityRegistryTransactor{contract: contract}, nil +} + +func NewCapabilityRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*CapabilityRegistryFilterer, error) { + contract, err := bindCapabilityRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &CapabilityRegistryFilterer{contract: contract}, nil +} + +func bindCapabilityRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := CapabilityRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_CapabilityRegistry *CapabilityRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _CapabilityRegistry.Contract.CapabilityRegistryCaller.contract.Call(opts, result, method, params...) +} + +func (_CapabilityRegistry *CapabilityRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.CapabilityRegistryTransactor.contract.Transfer(opts) +} + +func (_CapabilityRegistry *CapabilityRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.CapabilityRegistryTransactor.contract.Transact(opts, method, params...) +} + +func (_CapabilityRegistry *CapabilityRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _CapabilityRegistry.Contract.contract.Call(opts, result, method, params...) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.contract.Transfer(opts) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.contract.Transact(opts, method, params...) +} + +func (_CapabilityRegistry *CapabilityRegistryCaller) GetCapability(opts *bind.CallOpts, capabilityID [32]byte) (Capability, error) { + var out []interface{} + err := _CapabilityRegistry.contract.Call(opts, &out, "getCapability", capabilityID) + + if err != nil { + return *new(Capability), err + } + + out0 := *abi.ConvertType(out[0], new(Capability)).(*Capability) + + return out0, err + +} + +func (_CapabilityRegistry *CapabilityRegistrySession) GetCapability(capabilityID [32]byte) (Capability, error) { + return _CapabilityRegistry.Contract.GetCapability(&_CapabilityRegistry.CallOpts, capabilityID) +} + +func (_CapabilityRegistry *CapabilityRegistryCallerSession) GetCapability(capabilityID [32]byte) (Capability, error) { + return _CapabilityRegistry.Contract.GetCapability(&_CapabilityRegistry.CallOpts, capabilityID) +} + +func (_CapabilityRegistry *CapabilityRegistryCaller) GetCapabilityID(opts *bind.CallOpts, capabilityType [32]byte, version [32]byte) ([32]byte, error) { + var out []interface{} + err := _CapabilityRegistry.contract.Call(opts, &out, "getCapabilityID", capabilityType, version) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_CapabilityRegistry *CapabilityRegistrySession) GetCapabilityID(capabilityType [32]byte, version [32]byte) ([32]byte, error) { + return _CapabilityRegistry.Contract.GetCapabilityID(&_CapabilityRegistry.CallOpts, capabilityType, version) +} + +func (_CapabilityRegistry *CapabilityRegistryCallerSession) GetCapabilityID(capabilityType [32]byte, version [32]byte) ([32]byte, error) { + return _CapabilityRegistry.Contract.GetCapabilityID(&_CapabilityRegistry.CallOpts, capabilityType, version) +} + +func (_CapabilityRegistry *CapabilityRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _CapabilityRegistry.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_CapabilityRegistry *CapabilityRegistrySession) Owner() (common.Address, error) { + return _CapabilityRegistry.Contract.Owner(&_CapabilityRegistry.CallOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryCallerSession) Owner() (common.Address, error) { + return _CapabilityRegistry.Contract.Owner(&_CapabilityRegistry.CallOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _CapabilityRegistry.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_CapabilityRegistry *CapabilityRegistrySession) TypeAndVersion() (string, error) { + return _CapabilityRegistry.Contract.TypeAndVersion(&_CapabilityRegistry.CallOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryCallerSession) TypeAndVersion() (string, error) { + return _CapabilityRegistry.Contract.TypeAndVersion(&_CapabilityRegistry.CallOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _CapabilityRegistry.contract.Transact(opts, "acceptOwnership") +} + +func (_CapabilityRegistry *CapabilityRegistrySession) AcceptOwnership() (*types.Transaction, error) { + return _CapabilityRegistry.Contract.AcceptOwnership(&_CapabilityRegistry.TransactOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _CapabilityRegistry.Contract.AcceptOwnership(&_CapabilityRegistry.TransactOpts) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactor) AddCapability(opts *bind.TransactOpts, capability Capability) (*types.Transaction, error) { + return _CapabilityRegistry.contract.Transact(opts, "addCapability", capability) +} + +func (_CapabilityRegistry *CapabilityRegistrySession) AddCapability(capability Capability) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.AddCapability(&_CapabilityRegistry.TransactOpts, capability) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactorSession) AddCapability(capability Capability) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.AddCapability(&_CapabilityRegistry.TransactOpts, capability) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _CapabilityRegistry.contract.Transact(opts, "transferOwnership", to) +} + +func (_CapabilityRegistry *CapabilityRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.TransferOwnership(&_CapabilityRegistry.TransactOpts, to) +} + +func (_CapabilityRegistry *CapabilityRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _CapabilityRegistry.Contract.TransferOwnership(&_CapabilityRegistry.TransactOpts, to) +} + +type CapabilityRegistryCapabilityAddedIterator struct { + Event *CapabilityRegistryCapabilityAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *CapabilityRegistryCapabilityAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryCapabilityAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryCapabilityAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *CapabilityRegistryCapabilityAddedIterator) Error() error { + return it.fail +} + +func (it *CapabilityRegistryCapabilityAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type CapabilityRegistryCapabilityAdded struct { + CapabilityId [32]byte + Raw types.Log +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) FilterCapabilityAdded(opts *bind.FilterOpts, capabilityId [][32]byte) (*CapabilityRegistryCapabilityAddedIterator, error) { + + var capabilityIdRule []interface{} + for _, capabilityIdItem := range capabilityId { + capabilityIdRule = append(capabilityIdRule, capabilityIdItem) + } + + logs, sub, err := _CapabilityRegistry.contract.FilterLogs(opts, "CapabilityAdded", capabilityIdRule) + if err != nil { + return nil, err + } + return &CapabilityRegistryCapabilityAddedIterator{contract: _CapabilityRegistry.contract, event: "CapabilityAdded", logs: logs, sub: sub}, nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) WatchCapabilityAdded(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryCapabilityAdded, capabilityId [][32]byte) (event.Subscription, error) { + + var capabilityIdRule []interface{} + for _, capabilityIdItem := range capabilityId { + capabilityIdRule = append(capabilityIdRule, capabilityIdItem) + } + + logs, sub, err := _CapabilityRegistry.contract.WatchLogs(opts, "CapabilityAdded", capabilityIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(CapabilityRegistryCapabilityAdded) + if err := _CapabilityRegistry.contract.UnpackLog(event, "CapabilityAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) ParseCapabilityAdded(log types.Log) (*CapabilityRegistryCapabilityAdded, error) { + event := new(CapabilityRegistryCapabilityAdded) + if err := _CapabilityRegistry.contract.UnpackLog(event, "CapabilityAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type CapabilityRegistryOwnershipTransferRequestedIterator struct { + Event *CapabilityRegistryOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *CapabilityRegistryOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *CapabilityRegistryOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *CapabilityRegistryOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type CapabilityRegistryOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CapabilityRegistryOwnershipTransferRequestedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _CapabilityRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &CapabilityRegistryOwnershipTransferRequestedIterator{contract: _CapabilityRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _CapabilityRegistry.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(CapabilityRegistryOwnershipTransferRequested) + if err := _CapabilityRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*CapabilityRegistryOwnershipTransferRequested, error) { + event := new(CapabilityRegistryOwnershipTransferRequested) + if err := _CapabilityRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type CapabilityRegistryOwnershipTransferredIterator struct { + Event *CapabilityRegistryOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *CapabilityRegistryOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(CapabilityRegistryOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *CapabilityRegistryOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *CapabilityRegistryOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type CapabilityRegistryOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CapabilityRegistryOwnershipTransferredIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _CapabilityRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &CapabilityRegistryOwnershipTransferredIterator{contract: _CapabilityRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _CapabilityRegistry.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(CapabilityRegistryOwnershipTransferred) + if err := _CapabilityRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_CapabilityRegistry *CapabilityRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*CapabilityRegistryOwnershipTransferred, error) { + event := new(CapabilityRegistryOwnershipTransferred) + if err := _CapabilityRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_CapabilityRegistry *CapabilityRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _CapabilityRegistry.abi.Events["CapabilityAdded"].ID: + return _CapabilityRegistry.ParseCapabilityAdded(log) + case _CapabilityRegistry.abi.Events["OwnershipTransferRequested"].ID: + return _CapabilityRegistry.ParseOwnershipTransferRequested(log) + case _CapabilityRegistry.abi.Events["OwnershipTransferred"].ID: + return _CapabilityRegistry.ParseOwnershipTransferred(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (CapabilityRegistryCapabilityAdded) Topic() common.Hash { + return common.HexToHash("0x65610e5677eedff94555572640e442f89848a109ef8593fa927ac30b2565ff06") +} + +func (CapabilityRegistryOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (CapabilityRegistryOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (_CapabilityRegistry *CapabilityRegistry) Address() common.Address { + return _CapabilityRegistry.address +} + +type CapabilityRegistryInterface interface { + GetCapability(opts *bind.CallOpts, capabilityID [32]byte) (Capability, error) + + GetCapabilityID(opts *bind.CallOpts, capabilityType [32]byte, version [32]byte) ([32]byte, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AddCapability(opts *bind.TransactOpts, capability Capability) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterCapabilityAdded(opts *bind.FilterOpts, capabilityId [][32]byte) (*CapabilityRegistryCapabilityAddedIterator, error) + + WatchCapabilityAdded(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryCapabilityAdded, capabilityId [][32]byte) (event.Subscription, error) + + ParseCapabilityAdded(log types.Log) (*CapabilityRegistryCapabilityAdded, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CapabilityRegistryOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*CapabilityRegistryOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CapabilityRegistryOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CapabilityRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*CapabilityRegistryOwnershipTransferred, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt index b9d8bfbfefc..98fd35e188b 100644 --- a/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,3 +1,4 @@ GETH_VERSION: 1.13.8 -forwarder: ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.bin 4886b538e1fdc8aaf860901de36269e0c35acfd3e6eb190654d693ff9dbd4b6d +forwarder: ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.bin b4c900aae9e022f01abbac7993d41f93912247613ac6270b0c4da4ef6f2016e3 +keystone_capability_registry: ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.abi ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.bin fbaf8eceb929494bdfe0028921a0742da525cb4ec1b6d57a1382eda46fa32c64 ocr3_capability: ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.abi ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.bin 9dcbdf55bd5729ba266148da3f17733eb592c871c2108ccca546618628fd9ad2 diff --git a/core/gethwrappers/keystone/go_generate.go b/core/gethwrappers/keystone/go_generate.go index 0c49456f29c..679b678b8f2 100644 --- a/core/gethwrappers/keystone/go_generate.go +++ b/core/gethwrappers/keystone/go_generate.go @@ -6,3 +6,4 @@ package gethwrappers //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.bin KeystoneForwarder forwarder //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.abi ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.bin OCR3Capability ocr3_capability +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.abi ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.bin CapabilityRegistry keystone_capability_registry diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 3a92269cc03..8123439dafb 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -38,6 +38,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" @@ -182,7 +183,7 @@ type JobPipelineConfig interface { func NewJobPipelineV2(t testing.TB, cfg pipeline.BridgeConfig, jpcfg JobPipelineConfig, dbCfg pg.QConfig, legacyChains legacyevm.LegacyChainContainer, db *sqlx.DB, keyStore keystore.Master, restrictedHTTPClient, unrestrictedHTTPClient *http.Client) JobPipelineV2TestHelper { lggr := logger.TestLogger(t) - prm := pipeline.NewORM(db, lggr, dbCfg, jpcfg.MaxSuccessfulRuns()) + prm := pipeline.NewORM(db, lggr, jpcfg.MaxSuccessfulRuns()) btORM := bridges.NewORM(db) jrm := job.NewORM(db, prm, btORM, keyStore, lggr, dbCfg) pr := pipeline.NewRunner(prm, btORM, jpcfg, cfg, legacyChains, keyStore.Eth(), keyStore.VRF(), lggr, restrictedHTTPClient, unrestrictedHTTPClient) @@ -263,18 +264,19 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla } func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID ubig.Big) { - require.NoError(t, app.KeyStore.Unlock(Password)) + ctx := testutils.Context(t) + require.NoError(t, app.KeyStore.Unlock(ctx, Password)) for _, dep := range flagsAndDeps { switch v := dep.(type) { case ethkey.KeyV2: app.Keys = append(app.Keys, v) case p2pkey.KeyV2: - require.NoError(t, app.GetKeyStore().P2P().Add(v)) + require.NoError(t, app.GetKeyStore().P2P().Add(ctx, v)) case csakey.KeyV2: - require.NoError(t, app.GetKeyStore().CSA().Add(v)) + require.NoError(t, app.GetKeyStore().CSA().Add(ctx, v)) case ocr2key.KeyBundle: - require.NoError(t, app.GetKeyStore().OCR2().Add(v)) + require.NoError(t, app.GetKeyStore().OCR2().Add(ctx, v)) } } @@ -341,7 +343,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } } - keyStore := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + keyStore := keystore.NewInMemory(db, utils.FastScryptParams, lggr) mailMon := mailbox.NewMonitor(cfg.AppID().String(), lggr.Named("Mailbox")) loopRegistry := plugins.NewLoopRegistry(lggr, nil) @@ -534,7 +536,7 @@ func NewEthMocksWithTransactionsOnBlocksAssertions(t testing.TB) *evmclimocks.Cl func (ta *TestApplication) Start(ctx context.Context) error { ta.t.Helper() ta.Started = true - err := ta.ChainlinkApplication.KeyStore.Unlock(Password) + err := ta.ChainlinkApplication.KeyStore.Unlock(ctx, Password) if err != nil { return err } @@ -576,7 +578,7 @@ func (ta *TestApplication) MustSeedNewSession(email string) (id string) { // ImportKey adds private key to the application keystore and database func (ta *TestApplication) Import(ctx context.Context, content string) { - require.NoError(ta.t, ta.KeyStore.Unlock(Password)) + require.NoError(ta.t, ta.KeyStore.Unlock(ctx, Password)) _, err := ta.KeyStore.Eth().Import(ctx, []byte(content), Password, &FixtureChainID) require.NoError(ta.t, err) } @@ -661,9 +663,10 @@ func (ta *TestApplication) NewAuthenticatingShell(prompter cmd.Prompter) *cmd.Sh } // NewKeyStore returns a new, unlocked keystore -func NewKeyStore(t testing.TB, db *sqlx.DB, cfg pg.QConfig) keystore.Master { - keystore := keystore.NewInMemory(db, utils.FastScryptParams, logger.TestLogger(t), cfg) - require.NoError(t, keystore.Unlock(Password)) +func NewKeyStore(t testing.TB, ds sqlutil.DataSource) keystore.Master { + ctx := testutils.Context(t) + keystore := keystore.NewInMemory(ds, utils.FastScryptParams, logger.TestLogger(t)) + require.NoError(t, keystore.Unlock(ctx, Password)) return keystore } @@ -1511,8 +1514,8 @@ func EventuallyExpectationsMet(t *testing.T, mock testifyExpectationsAsserter, t } } -func AssertCount(t *testing.T, db *sqlx.DB, tableName string, expected int64) { - testutils.AssertCount(t, db, tableName, expected) +func AssertCount(t *testing.T, ds sqlutil.DataSource, tableName string, expected int64) { + testutils.AssertCount(t, ds, tableName, expected) } func WaitForCount(t *testing.T, db *sqlx.DB, tableName string, want int64) { @@ -1560,8 +1563,8 @@ func NewTestChainScopedConfig(t testing.TB) evmconfig.ChainScopedConfig { return evmtest.NewChainScopedConfig(t, cfg) } -func NewTestTxStore(t *testing.T, db *sqlx.DB) txmgr.TestEvmTxStore { - return txmgr.NewTxStore(db, logger.TestLogger(t)) +func NewTestTxStore(t *testing.T, ds sqlutil.DataSource) txmgr.TestEvmTxStore { + return txmgr.NewTxStore(ds, logger.TestLogger(t)) } // ClearDBTables deletes all rows from the given tables diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index d7e1036bcac..43cf902ca8a 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -402,7 +402,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm *keeper.ORM, from evmty cfg := configtest.NewTestGeneralConfig(t) tlg := logger.TestLogger(t) - prm := pipeline.NewORM(db, tlg, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + prm := pipeline.NewORM(db, tlg, cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) jrm := job.NewORM(db, prm, btORM, nil, tlg, cfg.Database()) err = jrm.InsertJob(&jb) diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index 5d8f75e36c3..d78440838b2 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -43,12 +44,13 @@ func MinimalOCRNonBootstrapSpec(contractAddress, transmitterAddress types.EIP55A } func MustInsertWebhookSpec(t *testing.T, db *sqlx.DB) (job.Job, job.WebhookSpec) { + ctx := testutils.Context(t) jobORM, pipelineORM := getORMs(t, db) webhookSpec := job.WebhookSpec{} require.NoError(t, jobORM.InsertWebhookSpec(&webhookSpec)) pSpec := pipeline.Pipeline{} - pipelineSpecID, err := pipelineORM.CreateSpec(pSpec, 0) + pipelineSpecID, err := pipelineORM.CreateSpec(ctx, nil, pSpec, 0) require.NoError(t, err) createdJob := job.Job{WebhookSpecID: &webhookSpec.ID, WebhookSpec: &webhookSpec, SchemaVersion: 1, Type: "webhook", @@ -60,9 +62,9 @@ func MustInsertWebhookSpec(t *testing.T, db *sqlx.DB) (job.Job, job.WebhookSpec) func getORMs(t *testing.T, db *sqlx.DB) (jobORM job.ORM, pipelineORM pipeline.ORM) { config := configtest.NewTestGeneralConfig(t) - keyStore := NewKeyStore(t, db, config.Database()) + keyStore := NewKeyStore(t, db) lggr := logger.TestLogger(t) - pipelineORM = pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM = pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db) jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) t.Cleanup(func() { jobORM.Close() }) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 2c40c848263..75ff98d05be 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -236,7 +236,7 @@ observationSource = """ _ = cltest.CreateJobRunViaExternalInitiatorV2(t, app, jobUUID, *eia, cltest.MustJSONMarshal(t, eiRequest)) - pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(app.GetSqlxDB()) jobORM := job.NewORM(app.GetSqlxDB(), pipelineORM, bridgeORM, app.KeyStore, logger.TestLogger(t), cfg.Database()) @@ -681,6 +681,7 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac func setupNode(t *testing.T, owner *bind.TransactOpts, portV2 int, b *backends.SimulatedBackend, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) (*cltest.TestApplication, string, common.Address, ocrkey.KeyV2) { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -719,12 +720,13 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV2 int, require.NoError(t, err) b.Commit() - key, err := app.GetKeyStore().OCR().Create() + key, err := app.GetKeyStore().OCR().Create(ctx) require.NoError(t, err) return app, p2pKey.PeerID().Raw(), transmitter, key } func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 int, b *backends.SimulatedBackend, overrides func(c *chainlink.Config, s *chainlink.Secrets)) (*cltest.TestApplication, string, common.Address, common.Address, ocrkey.KeyV2) { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -761,7 +763,7 @@ func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 in require.NoError(t, err) b.Commit() - key, err := app.GetKeyStore().OCR().Create() + key, err := app.GetKeyStore().OCR().Create(ctx) require.NoError(t, err) // deploy a forwarder @@ -867,7 +869,7 @@ func TestIntegration_OCR(t *testing.T) { err = appBootstrap.Start(testutils.Context(t)) require.NoError(t, err) - jb, err := ocr.ValidatedOracleSpecToml(appBootstrap.GetRelayers().LegacyEVMChains(), fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(appBootstrap.Config, appBootstrap.GetRelayers().LegacyEVMChains(), fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 name = "boot" @@ -936,7 +938,7 @@ isBootstrapPeer = true // Note we need: observationTimeout + observationGracePeriod + DeltaGrace (500ms) < DeltaRound (1s) // So 200ms + 200ms + 500ms < 1s - jb, err := ocr.ValidatedOracleSpecToml(apps[i].GetRelayers().LegacyEVMChains(), fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(apps[i].Config, apps[i].GetRelayers().LegacyEVMChains(), fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 name = "web oracle spec" @@ -1092,7 +1094,7 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { require.NoError(t, err) // set forwardingAllowed = true - jb, err := ocr.ValidatedOracleSpecToml(appBootstrap.GetRelayers().LegacyEVMChains(), fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(appBootstrap.Config, appBootstrap.GetRelayers().LegacyEVMChains(), fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 name = "boot" @@ -1163,7 +1165,7 @@ isBootstrapPeer = true // Note we need: observationTimeout + observationGracePeriod + DeltaGrace (500ms) < DeltaRound (1s) // So 200ms + 200ms + 500ms < 1s // forwardingAllowed = true - jb, err := ocr.ValidatedOracleSpecToml(apps[i].GetRelayers().LegacyEVMChains(), fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(apps[i].Config, apps[i].GetRelayers().LegacyEVMChains(), fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 name = "web oracle spec" @@ -1241,6 +1243,7 @@ observationSource = """ func TestIntegration_BlockHistoryEstimator(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) var initialDefaultGasPrice int64 = 5_000_000_000 maxGasPrice := assets.NewWeiI(10 * initialDefaultGasPrice) @@ -1260,8 +1263,8 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { chchNewHeads := make(chan evmtest.RawSub[*evmtypes.Head], 1) db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()) - require.NoError(t, kst.Unlock(cltest.Password)) + kst := cltest.NewKeyStore(t, db) + require.NoError(t, kst.Unlock(ctx, cltest.Password)) cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, KeyStore: kst.Eth(), Client: ethClient, GeneralConfig: cfg}) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 06f57c805ec..07e0fc21d9a 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -111,6 +111,7 @@ func setupNodeOCR2( b *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -157,7 +158,7 @@ func setupNodeOCR2( require.NoError(t, err) b.Commit() - kb, err := app.GetKeyStore().OCR2().Create("evm") + kb, err := app.GetKeyStore().OCR2().Create(ctx, "evm") require.NoError(t, err) if useForwarder { diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index c18cb7f8426..2438eb302c0 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/flags.go b/core/internal/mocks/flags.go index 32d21326ba0..3f9e47095e6 100644 --- a/core/internal/mocks/flags.go +++ b/core/internal/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go index ac72bd07db8..c1e35f41e2f 100644 --- a/core/internal/mocks/flux_aggregator.go +++ b/core/internal/mocks/flux_aggregator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go index 6573dbaf03f..81ff22d9d52 100644 --- a/core/internal/mocks/prometheus_backend.go +++ b/core/internal/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 83c356bf1a3..eedc6275928 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -37,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -53,7 +52,7 @@ func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.Chain } } - return evmconfig.NewTOMLChainScopedConfig(cfg, evmCfg, logger.TestLogger(t)) + return evmconfig.NewTOMLChainScopedConfig(evmCfg, logger.TestLogger(t)) } @@ -175,10 +174,10 @@ chains: } } -func (mo *TestConfigs) Chains(ids ...relay.ChainID) (cs []types.ChainStatus, count int, err error) { +func (mo *TestConfigs) Chains(chainIDs ...string) (cs []types.ChainStatus, count int, err error) { mo.mu.RLock() defer mo.mu.RUnlock() - if len(ids) == 0 { + if len(chainIDs) == 0 { for _, c := range mo.EVMConfigs { c2 := types.ChainStatus{ ID: c.ChainID.String(), @@ -196,7 +195,7 @@ func (mo *TestConfigs) Chains(ids ...relay.ChainID) (cs []types.ChainStatus, cou for i := range mo.EVMConfigs { c := mo.EVMConfigs[i] chainID := c.ChainID.String() - if !slices.Contains(ids, chainID) { + if !slices.Contains(chainIDs, chainID) { continue } c2 := types.ChainStatus{ @@ -214,19 +213,19 @@ func (mo *TestConfigs) Chains(ids ...relay.ChainID) (cs []types.ChainStatus, cou } // Nodes implements evmtypes.Configs -func (mo *TestConfigs) Nodes(id relay.ChainID) (nodes []evmtypes.Node, err error) { +func (mo *TestConfigs) Nodes(chainID string) (nodes []evmtypes.Node, err error) { mo.mu.RLock() defer mo.mu.RUnlock() for i := range mo.EVMConfigs { c := mo.EVMConfigs[i] - if id == c.ChainID.String() { + if chainID == c.ChainID.String() { for _, n := range c.Nodes { nodes = append(nodes, legacyNode(n, c.ChainID)) } } } - err = fmt.Errorf("no nodes: chain %s: %w", id, chains.ErrNotFound) + err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) return } diff --git a/core/internal/testutils/evmtest/v2/evmtest.go b/core/internal/testutils/evmtest/v2/evmtest.go index 22b2bc5e0ca..5621d91e748 100644 --- a/core/internal/testutils/evmtest/v2/evmtest.go +++ b/core/internal/testutils/evmtest/v2/evmtest.go @@ -6,7 +6,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -18,5 +17,5 @@ func ChainArbitrumRinkeby(t *testing.T) config.ChainScopedConfig { return scoped func scopedConfig(t *testing.T, chainID int64) config.ChainScopedConfig { id := big.NewI(chainID) evmCfg := toml.EVMConfig{ChainID: id, Chain: toml.Defaults(id)} - return config.NewTOMLChainScopedConfig(configtest.NewTestGeneralConfig(t), &evmCfg, logger.TestLogger(t)) + return config.NewTOMLChainScopedConfig(&evmCfg, logger.TestLogger(t)) } diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 9fdd50625cc..ba7e697fb62 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -24,15 +24,14 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" "github.com/gorilla/websocket" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tidwall/gjson" "go.uber.org/zap/zaptest/observer" - "github.com/jmoiron/sqlx" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" // NOTE: To avoid circular dependencies, this package MUST NOT import // anything from "github.com/smartcontractkit/chainlink/v2/core" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) const ( @@ -419,10 +418,10 @@ func SkipShortDB(tb testing.TB) { SkipShort(tb, "DB dependency") } -func AssertCount(t *testing.T, db *sqlx.DB, tableName string, expected int64) { +func AssertCount(t *testing.T, ds sqlutil.DataSource, tableName string, expected int64) { t.Helper() var count int64 - err := db.Get(&count, fmt.Sprintf(`SELECT count(*) FROM %s;`, tableName)) + err := ds.GetContext(Context(t), &count, fmt.Sprintf(`SELECT count(*) FROM %s;`, tableName)) require.NoError(t, err) require.Equal(t, expected, count) } diff --git a/core/logger/logger_mock_test.go b/core/logger/logger_mock_test.go index afddd031888..8d52734fe57 100644 --- a/core/logger/logger_mock_test.go +++ b/core/logger/logger_mock_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package logger diff --git a/core/logger/mocks/logger.go b/core/logger/mocks/logger.go index 316f6216b90..7e56bf8d22b 100644 --- a/core/logger/mocks/logger.go +++ b/core/logger/mocks/logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 5bffe1d7f4d..9441180e763 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -10,7 +10,7 @@ require ( github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.13.8 github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.5.0 github.com/jmoiron/sqlx v1.3.5 github.com/joho/godotenv v1.4.0 github.com/jonboulle/clockwork v0.4.0 @@ -21,10 +21,10 @@ 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.20240415164156-8872a8f311cb + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 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-20240326191951-2bbe9382d052 + github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.9.0 @@ -58,7 +58,6 @@ require ( github.com/XSAM/otelsql v0.27.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -117,8 +116,8 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gagliardetto/binary v0.7.1 // indirect - github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect + github.com/gagliardetto/binary v0.7.7 // indirect + github.com/gagliardetto/solana-go v1.8.4 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect @@ -249,6 +248,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect @@ -256,19 +256,20 @@ require ( github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.7.2 // indirect + github.com/smartcontractkit/wsrpc v0.8.1 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/status-im/keycard-go v0.2.0 // indirect + github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/supranational/blst v0.3.11 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect @@ -296,6 +297,7 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect + go.mongodb.org/mongo-driver v1.15.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 30315fa38ba..1f881b15778 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -156,8 +156,6 @@ github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= @@ -428,13 +426,12 @@ github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADi github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= -github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI= -github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= +github.com/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY= +github.com/gagliardetto/binary v0.7.7/go.mod h1:mUuay5LL8wFVnIlecHakSZMvcdqfs+CsotR5n77kyjM= github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 h1:q2IztKyRQUxJ6abXRsawaBtvDFvM+szj4jDqV4od1gs= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY= +github.com/gagliardetto/solana-go v1.8.4 h1:vmD/JmTlonyXGy39bAo0inMhmbdAwV7rXZtLDMZeodE= +github.com/gagliardetto/solana-go v1.8.4/go.mod h1:i+7aAyNDTHG0jK8GZIBSI4OVvDqkt2Qx+LklYclRNG8= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= @@ -582,6 +579,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -638,10 +636,9 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -997,6 +994,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -1187,16 +1185,16 @@ 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.20240415164156-8872a8f311cb h1:yLDt5cQWRwcFM5VEdSTbc3vDrYrxYqBjSvyTMU/o8s4= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240415164156-8872a8f311cb/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 h1:elDIBChe7ByPNvCyrSjMLTPKrgY+sKgzzlWe2p3wokY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9/go.mod h1:GTDBbovHUSAUk+fuGIySF2A/whhdtHGaWmU61BoERks= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 h1:MvaNzuaQh1vX4CAYLM8qFd99cf0ZF1JNwtDZtLU7WvU= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92/go.mod h1:uATrrJ8IsuBkOBJ46USuf73gz9gZy5k5bzGE5/ji/rc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab h1:Ct1oUlyn03HDUVdFHJqtRGRUujMqdoMzvf/Cjhe30Ag= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab/go.mod h1:RPUY7r8GxgzXxS1ijtU1P/fpJomOXztXgUbEziNmbCA= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 h1:jc4ab5QrKZfkICyxJysCt7mSExuSPbePjgZsnJR3nRQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58/go.mod h1:oV5gIuSKrPEcjQ6uB6smBsm5kXHxyydVLNyAs4V9CoQ= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= @@ -1205,14 +1203,14 @@ github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+ github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= -github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= +github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= +github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1242,6 +1240,8 @@ github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 h1:ZqpS7rAhhKD7S7DnrpEdrnW1/gZcv82ytpMviovkli4= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1289,6 +1289,7 @@ github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -1337,6 +1338,9 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1353,6 +1357,7 @@ github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dz github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA= github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= @@ -1382,6 +1387,9 @@ go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYr go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1438,7 +1446,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1464,11 +1472,12 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= @@ -1563,8 +1572,8 @@ golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1663,7 +1672,6 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1764,7 +1772,6 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= diff --git a/core/scripts/setup_testdb.sh b/core/scripts/setup_testdb.sh new file mode 100755 index 00000000000..8f30e159d1c --- /dev/null +++ b/core/scripts/setup_testdb.sh @@ -0,0 +1,66 @@ +#/bin/sh + +# Create a new user and database for development +# This script is intended to be run on a local development machine +tdir=$(mktemp -d -t db-dev-user) + +username="chainlink_dev" +password="insecurepassword" +database="chainlink_development_test" +# here document for the SQL commands +cat << EOF > $tdir/db-dev-user.sql +-- create a new user and database for development if they don't exist +DO \$\$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '$username') THEN + CREATE ROLE $username WITH LOGIN PASSWORD '$password'; + END IF; +END \$\$; +SELECT 'CREATE DATABASE $database WITH OWNER $username;' +WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$database')\gexec + +-- Grant all privileges on the database to the user +ALTER DATABASE $database OWNER TO $username; +GRANT ALL PRIVILEGES ON DATABASE "$database" TO "$username"; + +-- Create a pristine database for testing +SELECT 'CREATE DATABASE chainlink_test_pristine WITH OWNER $username;' +WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'chainlink_test_pristine')\gexec +EOF + +# Print the SQL commands +echo "SQL commands to be run: $tdir/db-dev-user.sql" +echo "##########################################################################################################" +echo "##########################################################################################################" + +cat $tdir/db-dev-user.sql +echo "##########################################################################################################" +echo "##########################################################################################################" +echo "" +# Run the SQL commands +psql -U postgres -h localhost -f $tdir/db-dev-user.sql + + +#test the connection +PGPASSWORD=$password psql -U $username -h localhost -d $database -c "SELECT 1" && echo "Connection successful" || echo "Connection failed" + +db_url=$(echo "CL_DATABASE_URL=postgresql://chainlink_dev:insecurepassword@localhost:5432/chainlink_development_test") +echo $db_url +repo=$(git rev-parse --show-toplevel) +pushd $repo +export $db_url +make testdb || echo "Failed to create test database" +popd + +# Set the database URL in the .dbenv file +dbenv=$repo/.dbenv +echo "\n!Success!\n" +echo "Datbase URL: $db_url" + +echo "export $db_url" >> $dbenv +echo "Has been set in the $dbenv file" + +echo "Either" +echo " source $dbenv" +echo "Or explicitly set environment variable in your shell" +echo " export $db_url" \ No newline at end of file diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 34070c90d8a..88f4d9e0f73 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -44,7 +44,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -54,6 +53,7 @@ var ( ) func main() { + ctx := context.Background() e := helpers.SetupEnv(false) switch os.Args[1] { @@ -218,8 +218,8 @@ func main() { db := sqlx.MustOpen("postgres", *dbURL) lggr, _ := logger.NewLogger() - keyStore := keystore.New(db, utils.DefaultScryptParams, lggr, pg.NewQConfig(false)) - err = keyStore.Unlock(*keystorePassword) + keyStore := keystore.New(db, utils.DefaultScryptParams, lggr) + err = keyStore.Unlock(ctx, *keystorePassword) helpers.PanicErr(err) k, err := keyStore.VRF().Get(*pubKeyHex) @@ -310,8 +310,8 @@ func main() { db := sqlx.MustOpen("postgres", *dbURL) lggr, _ := logger.NewLogger() - keyStore := keystore.New(db, utils.DefaultScryptParams, lggr, pg.NewQConfig(false)) - err = keyStore.Unlock(*keystorePassword) + keyStore := keystore.New(db, utils.DefaultScryptParams, lggr) + err = keyStore.Unlock(ctx, *keystorePassword) helpers.PanicErr(err) k, err := keyStore.VRF().Get(*pubKeyHex) diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 45ef7314bee..56d6855d54e 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -45,7 +45,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/extraargs" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -56,6 +55,7 @@ var ( ) func main() { + ctx := context.Background() e := helpers.SetupEnv(false) switch os.Args[1] { @@ -196,8 +196,8 @@ func main() { db := sqlx.MustOpen("postgres", *dbURL) lggr, _ := logger.NewLogger() - keyStore := keystore.New(db, utils.DefaultScryptParams, lggr, pg.NewQConfig(false)) - err = keyStore.Unlock(*keystorePassword) + keyStore := keystore.New(db, utils.DefaultScryptParams, lggr) + err = keyStore.Unlock(ctx, *keystorePassword) helpers.PanicErr(err) k, err := keyStore.VRF().Get(*pubKeyHex) @@ -292,8 +292,8 @@ func main() { db := sqlx.MustOpen("postgres", *dbURL) lggr, _ := logger.NewLogger() - keyStore := keystore.New(db, utils.DefaultScryptParams, lggr, pg.NewQConfig(false)) - err = keyStore.Unlock(*keystorePassword) + keyStore := keystore.New(db, utils.DefaultScryptParams, lggr) + err = keyStore.Unlock(ctx, *keystorePassword) helpers.PanicErr(err) k, err := keyStore.VRF().Get(*pubKeyHex) @@ -597,6 +597,24 @@ func main() { tx, err := coordinator.DeregisterProvingKey(e.Owner, [2]*big.Int{pk.X, pk.Y}) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) + case "coordinator-register-migratable-coordinator": + coordinatorRegisterMigratableCoordinator := flag.NewFlagSet("coordinator-register-migratable-coordinator", flag.ExitOnError) + coordinatorAddress := coordinatorRegisterMigratableCoordinator.String("address", "", "coordinator address from which to register migratable coordinator") + coordinatorMigrateToAddress := coordinatorRegisterMigratableCoordinator.String("coordinator-migrate-to-address", "", "coordinator address to register in order for perform sub migration to") + helpers.ParseArgs(coordinatorRegisterMigratableCoordinator, os.Args[2:], "address", "coordinator-migrate-to-address") + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) + helpers.PanicErr(err) + v2plusscripts.RegisterMigratableCoordinator(e, *coordinator, common.HexToAddress(*coordinatorMigrateToAddress)) + case "coordinator-migrate-sub": + coordinatorMigrateSub := flag.NewFlagSet("coordinator-migrate-sub", flag.ExitOnError) + coordinatorAddress := coordinatorMigrateSub.String("address", "", "coordinator address from which to migrate a sub") + coordinatorMigrateToAddress := coordinatorMigrateSub.String("coordinator-migrate-to-address", "", "coordinator address to migrate sub to") + subID := coordinatorMigrateSub.String("sub-id", "", "sub-id") + helpers.ParseArgs(coordinatorMigrateSub, os.Args[2:], "address", "coordinator-migrate-to-address", "sub-id") + parsedSubID := parseUInt256String(*subID) + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) + helpers.PanicErr(err) + v2plusscripts.MigrateSub(e, *coordinator, common.HexToAddress(*coordinatorMigrateToAddress), parsedSubID) case "coordinator-subscription": coordinatorSub := flag.NewFlagSet("coordinator-subscription", flag.ExitOnError) address := coordinatorSub.String("address", "", "coordinator address") @@ -1189,7 +1207,8 @@ func main() { cmd := flag.NewFlagSet("wrapper-configure", flag.ExitOnError) wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") wrapperGasOverhead := cmd.Uint("wrapper-gas-overhead", 50_000, "amount of gas overhead in wrapper fulfillment") - coordinatorGasOverhead := cmd.Uint("coordinator-gas-overhead", 52_000, "amount of gas overhead in coordinator fulfillment") + coordinatorGasOverheadNative := cmd.Uint("coordinator-gas-overhead-native", 52_000, "amount of gas overhead in coordinator fulfillment for native payment") + coordinatorGasOverheadLink := cmd.Uint("coordinator-gas-overhead-link", 52_000, "amount of gas overhead in coordinator fulfillment for link payment") coordinatorGasOverheadPerWord := cmd.Uint("coordinator-gas-overhead-per-word", 0, "amount of gas overhead in coordinator fulfillment") wrapperNativePremiumPercentage := cmd.Uint("wrapper-native-premium-percentage", 25, "gas premium charged by wrapper for native payment") wrapperLinkPremiumPercentage := cmd.Uint("wrapper-link-premium-percentage", 25, "gas premium charged by wrapper for link payment") @@ -1204,7 +1223,8 @@ func main() { v2plusscripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, - *coordinatorGasOverhead, + *coordinatorGasOverheadNative, + *coordinatorGasOverheadLink, *coordinatorGasOverheadPerWord, *wrapperNativePremiumPercentage, *wrapperLinkPremiumPercentage, diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 831b258fb6e..f749a8a2ef7 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -869,7 +869,8 @@ func DeployWrapperUniverse(e helpers.Environment) { coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") subscriptionID := cmd.String("subscription-id", "", "subscription ID for the wrapper") wrapperGasOverhead := cmd.Uint("wrapper-gas-overhead", 50_000, "amount of gas overhead in wrapper fulfillment") - coordinatorGasOverhead := cmd.Uint("coordinator-gas-overhead", 52_000, "amount of gas overhead in coordinator fulfillment") + coordinatorGasOverheadNative := cmd.Uint("coordinator-gas-overhead-native", 52_000, "amount of gas overhead in coordinator fulfillment for native payment") + coordinatorGasOverheadLink := cmd.Uint("coordinator-gas-overhead-link", 74_000, "amount of gas overhead in coordinator fulfillment for link payment") coordinatorGasOverheadPerWord := cmd.Uint("coordinator-gas-overhead-per-word", 0, "amount of gas overhead per word in coordinator fulfillment") wrapperNativePremiumPercentage := cmd.Uint("wrapper-native-premium-percentage", 25, "gas premium charged by wrapper for native payment") wrapperLinkPremiumPercentage := cmd.Uint("wrapper-link-premium-percentage", 25, "gas premium charged by wrapper for link payment") @@ -899,7 +900,8 @@ func DeployWrapperUniverse(e helpers.Environment) { WrapperConfigure(e, wrapper, *wrapperGasOverhead, - *coordinatorGasOverhead, + *coordinatorGasOverheadNative, + *coordinatorGasOverheadLink, *coordinatorGasOverheadPerWord, *wrapperNativePremiumPercentage, *wrapperLinkPremiumPercentage, diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index 8becb31239c..6fbdc88b869 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -198,6 +198,41 @@ func RegisterCoordinatorProvingKey(e helpers.Environment, ) } +func RegisterMigratableCoordinator( + e helpers.Environment, + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, + coordinatorMigrateToAddress common.Address, +) { + tx, err := coordinator.RegisterMigratableCoordinator(e.Owner, coordinatorMigrateToAddress) + helpers.PanicErr(err) + helpers.ConfirmTXMined( + context.Background(), + e.Ec, + tx, + e.ChainID, + fmt.Sprintf("Coordinator %s registered migratable coordinator %s", coordinator.Address().String(), coordinatorMigrateToAddress.String()), + ) +} + +func MigrateSub( + e helpers.Environment, + coordinatorMigrateSubFrom vrf_coordinator_v2_5.VRFCoordinatorV25, + coordinatorMigrateSubTo common.Address, + subID *big.Int, +) { + tx, err := coordinatorMigrateSubFrom.Migrate(e.Owner, subID, coordinatorMigrateSubTo) + helpers.PanicErr(err) + helpers.ConfirmTXMined( + context.Background(), + e.Ec, + tx, + e.ChainID, + fmt.Sprintf("Sub Migrated from Coordinator: %s,", coordinatorMigrateSubFrom.Address().String()), + fmt.Sprintf("Sub Migrated TO Coordinator: %s,", coordinatorMigrateSubTo.String()), + fmt.Sprintf("Sub ID which was migrated: %s,", subID.String()), + ) +} + func WrapperDeploy( e helpers.Environment, link, linkEthFeed, coordinator common.Address, subID *big.Int, @@ -219,7 +254,8 @@ func WrapperConfigure( e helpers.Environment, wrapperAddress common.Address, wrapperGasOverhead uint, - coordinatorGasOverhead, coordinatorGasOverheadPerWord uint, + coordinatorGasOverheadNative, coordinatorGasOverheadLink uint, + coordinatorGasOverheadPerWord uint, nativePremiumPercentage, linkPremiumPercentage uint, keyHash string, maxNumWords uint, @@ -234,7 +270,8 @@ func WrapperConfigure( tx, err := wrapper.SetConfig( e.Owner, uint32(wrapperGasOverhead), - uint32(coordinatorGasOverhead), + uint32(coordinatorGasOverheadNative), + uint32(coordinatorGasOverheadLink), uint16(coordinatorGasOverheadPerWord), uint8(nativePremiumPercentage), uint8(linkPremiumPercentage), diff --git a/core/services/blockhashstore/bhs.go b/core/services/blockhashstore/bhs.go index d4dd52c5661..4d1fe761c88 100644 --- a/core/services/blockhashstore/bhs.go +++ b/core/services/blockhashstore/bhs.go @@ -104,7 +104,7 @@ func (c *BulletproofBHS) Store(ctx context.Context, blockNum uint64) error { // Set a queue size of 256. At most we store the blockhash of every block, and only the // latest 256 can possibly be stored. - Strategy: txmgrcommon.NewQueueingTxStrategy(c.jobID, 256, c.dbConfig.DefaultQueryTimeout()), + Strategy: txmgrcommon.NewQueueingTxStrategy(c.jobID, 256), }) if err != nil { return errors.Wrap(err, "creating transaction") diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 75424ee8059..b2e978293df 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -28,15 +28,15 @@ func TestStoreRotatesFromAddresses(t *testing.T) { db := pgtest.NewSqlxDB(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewTestGeneralConfig(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()) - require.NoError(t, kst.Unlock(cltest.Password)) + kst := cltest.NewKeyStore(t, db) + require.NoError(t, kst.Unlock(ctx, cltest.Password)) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, KeyStore: kst.Eth(), GeneralConfig: cfg, Client: ethClient}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) chain, err := legacyChains.Get(cltest.FixtureChainID.String()) require.NoError(t, err) lggr := logger.TestLogger(t) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) - require.NoError(t, ks.Unlock("blah")) + ks := keystore.New(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, "blah")) k1, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) k2, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) @@ -49,7 +49,7 @@ func TestStoreRotatesFromAddresses(t *testing.T) { require.NoError(t, err) bhs, err := blockhashstore.NewBulletproofBHS( chain.Config().EVM().GasEstimator(), - chain.Config().Database(), + cfg.Database(), fromAddresses, txm, store, diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 9a11c057c32..3c5109f82c1 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -2,6 +2,7 @@ package blockhashstore import ( "context" + "encoding/json" "fmt" "sync" "time" @@ -11,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/trusted_blockhash_store" @@ -19,14 +21,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ job.ServiceCtx = &service{} +type Config interface { + Feature() config.Feature + Database() config.Database +} + // Delegate creates BlockhashStore feeder jobs. type Delegate struct { + cfg Config logger logger.Logger legacyChains legacyevm.LegacyChainContainer ks keystore.Eth @@ -34,11 +41,13 @@ type Delegate struct { // NewDelegate creates a new Delegate. func NewDelegate( + cfg Config, logger logger.Logger, legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, ) *Delegate { return &Delegate{ + cfg: cfg, logger: logger, legacyChains: legacyChains, ks: ks, @@ -56,6 +65,11 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi return nil, errors.Errorf( "blockhashstore.Delegate expects a BlockhashStoreSpec to be present, got %+v", jb) } + marshalledJob, err := json.MarshalIndent(jb.BlockhashStoreSpec, "", " ") + if err != nil { + return nil, err + } + d.logger.Debugw("Creating services for job spec", "job", string(marshalledJob)) chain, err := d.legacyChains.Get(jb.BlockhashStoreSpec.EVMChainID.String()) if err != nil { @@ -63,7 +77,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi "getting chain ID %d: %w", jb.BlockhashStoreSpec.EVMChainID.ToInt(), err) } - if !chain.Config().Feature().LogPoller() { + if !d.cfg.Feature().LogPoller() { return nil, errors.New("log poller must be enabled to run blockhashstore") } @@ -146,7 +160,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi bpBHS, err := NewBulletproofBHS( chain.Config().EVM().GasEstimator(), - chain.Config().Database(), + d.cfg.Database(), fromAddresses, chain.TxManager(), bhs, @@ -194,7 +208,7 @@ func (d *Delegate) BeforeJobCreated(spec job.Job) {} func (d *Delegate) BeforeJobDeleted(spec job.Job) {} // OnDeleteJob satisfies the job.Delegate interface. -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // service is a job.Service that runs the BHS feeder every pollPeriod. type service struct { diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 4c37273f161..6bc93546605 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -33,7 +33,7 @@ func TestDelegate_JobType(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) - delegate := blockhashstore.NewDelegate(lggr, nil, nil) + delegate := blockhashstore.NewDelegate(nil, lggr, nil, nil) assert.Equal(t, job.BlockhashStore, delegate.JobType()) } @@ -55,7 +55,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { c.Feature.LogPoller = func(b bool) *bool { return &b }(true) }) db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + kst := cltest.NewKeyStore(t, db).Eth() sendingKey, _ := cltest.MustInsertRandomKey(t, kst) lp := &mocklp.LogPoller{} lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) @@ -72,7 +72,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { }, ) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - return blockhashstore.NewDelegate(lggr, legacyChains, kst), &testData{ + return blockhashstore.NewDelegate(cfg, lggr, legacyChains, kst), &testData{ ethClient: ethClient, ethKeyStore: kst, legacyChains: legacyChains, diff --git a/core/services/blockhashstore/mocks/bhs.go b/core/services/blockhashstore/mocks/bhs.go index a69016c8026..43b4769c029 100644 --- a/core/services/blockhashstore/mocks/bhs.go +++ b/core/services/blockhashstore/mocks/bhs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/blockhashstore/mocks/timer.go b/core/services/blockhashstore/mocks/timer.go index 4236bdf8d92..46212b4c021 100644 --- a/core/services/blockhashstore/mocks/timer.go +++ b/core/services/blockhashstore/mocks/timer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 19edb43bc23..d848ba7c61e 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -2,6 +2,7 @@ package blockheaderfeeder import ( "context" + "encoding/json" "fmt" "time" @@ -10,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -19,24 +21,31 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ job.ServiceCtx = &service{} +type Config interface { + Feature() config.Feature + Database() config.Database +} + type Delegate struct { + cfg Config logger logger.Logger legacyChains legacyevm.LegacyChainContainer ks keystore.Eth } func NewDelegate( + cfg Config, logger logger.Logger, legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, ) *Delegate { return &Delegate{ + cfg: cfg, logger: logger, legacyChains: legacyChains, ks: ks, @@ -53,6 +62,11 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi if jb.BlockHeaderFeederSpec == nil { return nil, errors.Errorf("Delegate expects a BlockHeaderFeederSpec to be present, got %+v", jb) } + marshalledJob, err := json.MarshalIndent(jb.BlockHeaderFeederSpec, "", " ") + if err != nil { + return nil, err + } + d.logger.Debugw("Creating services for job spec", "job", string(marshalledJob)) chain, err := d.legacyChains.Get(jb.BlockHeaderFeederSpec.EVMChainID.String()) if err != nil { @@ -60,7 +74,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi "getting chain ID %d: %w", jb.BlockHeaderFeederSpec.EVMChainID.ToInt(), err) } - if !chain.Config().Feature().LogPoller() { + if !d.cfg.Feature().LogPoller() { return nil, errors.New("log poller must be enabled to run blockheaderfeeder") } @@ -139,7 +153,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi coordinators = append(coordinators, coord) } - bpBHS, err := blockhashstore.NewBulletproofBHS(chain.Config().EVM().GasEstimator(), chain.Config().Database(), fromAddresses, chain.TxManager(), bhs, nil, chain.ID(), d.ks) + bpBHS, err := blockhashstore.NewBulletproofBHS(chain.Config().EVM().GasEstimator(), d.cfg.Database(), fromAddresses, chain.TxManager(), bhs, nil, chain.ID(), d.ks) if err != nil { return nil, errors.Wrap(err, "building bulletproof bhs") } @@ -208,7 +222,7 @@ func (d *Delegate) BeforeJobCreated(spec job.Job) {} func (d *Delegate) BeforeJobDeleted(spec job.Job) {} // OnDeleteJob satisfies the job.Delegate interface. -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // service is a job.Service that runs the BHS feeder every pollPeriod. type service struct { diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 832bea523b5..88a6fadf345 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -308,7 +308,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } var ( - pipelineORM = pipeline.NewORM(sqlxDB, globalLogger, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + pipelineORM = pipeline.NewORM(sqlxDB, globalLogger, cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM = bridges.NewORM(sqlxDB) mercuryORM = mercury.NewORM(opts.DB) pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) @@ -333,6 +333,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { legacyEVMChains, mailMon), job.Keeper: keeper.NewDelegate( + cfg, sqlxDB, jobORM, pipelineRunner, @@ -346,7 +347,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { pipelineORM, legacyEVMChains, globalLogger, - cfg.Database(), mailMon), job.Webhook: webhook.NewDelegate( pipelineRunner, @@ -356,10 +356,12 @@ func NewApplication(opts ApplicationOpts) (Application, error) { pipelineRunner, globalLogger), job.BlockhashStore: blockhashstore.NewDelegate( + cfg, globalLogger, legacyEVMChains, keyStore.Eth()), job.BlockHeaderFeeder: blockheaderfeeder.NewDelegate( + cfg, globalLogger, legacyEVMChains, keyStore.Eth()), @@ -388,6 +390,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { delegates[job.FluxMonitor] = &job.NullDelegate{Type: job.FluxMonitor} } else { delegates[job.FluxMonitor] = fluxmonitorv2.NewDelegate( + cfg, keyStore.Eth(), jobORM, pipelineORM, @@ -421,7 +424,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { telemetryManager, legacyEVMChains, globalLogger, - cfg.Database(), + cfg, mailMon, ) } else { @@ -495,6 +498,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { sqlxDB, jobSpawner, keyStore, + cfg, cfg.Insecure(), cfg.JobPipeline(), cfg.OCR(), @@ -829,7 +833,7 @@ func (app *ChainlinkApplication) ResumeJobV2( taskID uuid.UUID, result pipeline.Result, ) error { - return app.pipelineRunner.ResumeRun(taskID, result.Value, result.Error) + return app.pipelineRunner.ResumeRun(ctx, taskID, result.Value, result.Error) } func (app *ChainlinkApplication) GetFeedsService() feeds.Service { diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index a520a878d3c..a86753a59e3 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index 4c552551008..6e47f6a1f9b 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -11,8 +11,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink-common/pkg/types" ) @@ -29,7 +27,7 @@ func (f *FakeRelayerChainInteroperators) LegacyEVMChains() legacyevm.LegacyChain return f.EVMChains } -func (f *FakeRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { +func (f *FakeRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...types.RelayID) (nodes []types.NodeStatus, count int, err error) { return slices.Clone(f.Nodes), len(f.Nodes), f.NodesErr } @@ -41,7 +39,7 @@ func (f *FakeRelayerChainInteroperators) List(filter chainlink.FilterFn) chainli panic("unimplemented") } -func (f *FakeRelayerChainInteroperators) Get(id relay.ID) (loop.Relayer, error) { +func (f *FakeRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, error) { panic("unimplemented") } @@ -53,7 +51,7 @@ func (f *FakeRelayerChainInteroperators) LegacyCosmosChains() chainlink.LegacyCo panic("unimplemented") } -func (f *FakeRelayerChainInteroperators) ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) { +func (f *FakeRelayerChainInteroperators) ChainStatus(ctx context.Context, id types.RelayID) (types.ChainStatus, error) { panic("unimplemented") } diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 673f71e3c65..e17d4d516e9 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -51,14 +51,14 @@ type LegacyChainer interface { } type ChainStatuser interface { - ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) + ChainStatus(ctx context.Context, id types.RelayID) (types.ChainStatus, error) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) } // NodesStatuser is an interface for node configuration and state. // TODO BCF-2440, BCF-2511 may need Node(ctx,name) to get a node status by name type NodesStatuser interface { - NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) + NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...types.RelayID) (nodes []types.NodeStatus, count int, err error) } // ChainsNodesStatuser report statuses about chains and nodes @@ -73,7 +73,7 @@ var _ RelayerChainInteroperators = &CoreRelayerChainInteroperators{} // as needed for the core [chainlink.Application] type CoreRelayerChainInteroperators struct { mu sync.Mutex - loopRelayers map[relay.ID]loop.Relayer + loopRelayers map[types.RelayID]loop.Relayer legacyChains legacyChains // we keep an explicit list of services because the legacy implementations have more than @@ -83,7 +83,7 @@ type CoreRelayerChainInteroperators struct { func NewCoreRelayerChainInteroperators(initFuncs ...CoreRelayerChainInitFunc) (*CoreRelayerChainInteroperators, error) { cr := &CoreRelayerChainInteroperators{ - loopRelayers: make(map[relay.ID]loop.Relayer), + loopRelayers: make(map[types.RelayID]loop.Relayer), srvs: make([]services.ServiceCtx, 0), } for _, initFn := range initFuncs { @@ -173,7 +173,7 @@ func InitStarknet(ctx context.Context, factory RelayerFactory, config StarkNetFa } // Get a [loop.Relayer] by id -func (rs *CoreRelayerChainInteroperators) Get(id relay.ID) (loop.Relayer, error) { +func (rs *CoreRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, error) { rs.mu.Lock() defer rs.mu.Unlock() lr, exist := rs.loopRelayers[id] @@ -200,7 +200,7 @@ func (rs *CoreRelayerChainInteroperators) LegacyCosmosChains() LegacyCosmosConta } // ChainStatus gets [types.ChainStatus] -func (rs *CoreRelayerChainInteroperators) ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) { +func (rs *CoreRelayerChainInteroperators) ChainStatus(ctx context.Context, id types.RelayID) (types.ChainStatus, error) { lr, err := rs.Get(id) if err != nil { @@ -219,7 +219,7 @@ func (rs *CoreRelayerChainInteroperators) ChainStatuses(ctx context.Context, off rs.mu.Lock() defer rs.mu.Unlock() - relayerIds := make([]relay.ID, 0) + relayerIds := make([]types.RelayID, 0) for rid := range rs.loopRelayers { relayerIds = append(relayerIds, rid) } @@ -263,7 +263,7 @@ func (rs *CoreRelayerChainInteroperators) Node(ctx context.Context, name string) // ids must be a string representation of relay.Identifier // ids are a filter; if none are specified, all are returned. -func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { +func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...types.RelayID) (nodes []types.NodeStatus, count int, err error) { var ( totalErr error result []types.NodeStatus @@ -304,15 +304,15 @@ func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offs return result[offset:], count, nil } -type FilterFn func(id relay.ID) bool +type FilterFn func(id types.RelayID) bool -var AllRelayers = func(id relay.ID) bool { +var AllRelayers = func(id types.RelayID) bool { return true } // Returns true if the given network matches id.Network -func FilterRelayersByType(network relay.Network) func(id relay.ID) bool { - return func(id relay.ID) bool { +func FilterRelayersByType(network string) func(id types.RelayID) bool { + return func(id types.RelayID) bool { return id.Network == network } } @@ -322,7 +322,7 @@ func FilterRelayersByType(network relay.Network) func(id relay.ID) bool { // for a given chain func (rs *CoreRelayerChainInteroperators) List(filter FilterFn) RelayerChainInteroperators { - matches := make(map[relay.ID]loop.Relayer) + matches := make(map[types.RelayID]loop.Relayer) rs.mu.Lock() for id, relayer := range rs.loopRelayers { if filter(id) { diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index c90811de768..7126c73927c 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -11,6 +11,7 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" @@ -25,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/plugins" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -172,7 +172,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) lggr := logger.TestLogger(t) @@ -187,23 +187,23 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { tests := []struct { name string initFuncs []chainlink.CoreRelayerChainInitFunc - expectedRelayerNetworks map[relay.Network]struct{} + expectedRelayerNetworks map[string]struct{} expectedEVMChainCnt int expectedEVMNodeCnt int - expectedEVMRelayerIds []relay.ID + expectedEVMRelayerIds []types.RelayID expectedSolanaChainCnt int expectedSolanaNodeCnt int - expectedSolanaRelayerIds []relay.ID + expectedSolanaRelayerIds []types.RelayID expectedStarknetChainCnt int expectedStarknetNodeCnt int - expectedStarknetRelayerIds []relay.ID + expectedStarknetRelayerIds []types.RelayID expectedCosmosChainCnt int expectedCosmosNodeCnt int - expectedCosmosRelayerIds []relay.ID + expectedCosmosRelayerIds []types.RelayID }{ {name: "2 evm chains with 3 nodes", @@ -220,11 +220,11 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, - expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: evmChainID1.String()}, - {Network: relay.EVM, ChainID: evmChainID2.String()}, + expectedEVMRelayerIds: []types.RelayID{ + {Network: types.NetworkEVM, ChainID: evmChainID1.String()}, + {Network: types.NetworkEVM, ChainID: evmChainID2.String()}, }, - expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}}, + expectedRelayerNetworks: map[string]struct{}{types.NetworkEVM: {}}, }, {name: "2 solana chain with 2 node", @@ -236,11 +236,11 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, - expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: solanaChainID1}, - {Network: relay.Solana, ChainID: solanaChainID2}, + expectedSolanaRelayerIds: []types.RelayID{ + {Network: types.NetworkSolana, ChainID: solanaChainID1}, + {Network: types.NetworkSolana, ChainID: solanaChainID2}, }, - expectedRelayerNetworks: map[relay.Network]struct{}{relay.Solana: {}}, + expectedRelayerNetworks: map[string]struct{}{types.NetworkSolana: {}}, }, {name: "2 starknet chain with 4 nodes", @@ -252,11 +252,11 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, - expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: starknetChainID1}, - {Network: relay.StarkNet, ChainID: starknetChainID2}, + expectedStarknetRelayerIds: []types.RelayID{ + {Network: types.NetworkStarkNet, ChainID: starknetChainID1}, + {Network: types.NetworkStarkNet, ChainID: starknetChainID2}, }, - expectedRelayerNetworks: map[relay.Network]struct{}{relay.StarkNet: {}}, + expectedRelayerNetworks: map[string]struct{}{types.NetworkStarkNet: {}}, }, { @@ -270,11 +270,11 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, - expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: cosmosChainID1}, - {Network: relay.Cosmos, ChainID: cosmosChainID2}, + expectedCosmosRelayerIds: []types.RelayID{ + {Network: types.NetworkCosmos, ChainID: cosmosChainID1}, + {Network: types.NetworkCosmos, ChainID: cosmosChainID2}, }, - expectedRelayerNetworks: map[relay.Network]struct{}{relay.Cosmos: {}}, + expectedRelayerNetworks: map[string]struct{}{types.NetworkCosmos: {}}, }, {name: "all chains", @@ -304,33 +304,33 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, - expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: evmChainID1.String()}, - {Network: relay.EVM, ChainID: evmChainID2.String()}, + expectedEVMRelayerIds: []types.RelayID{ + {Network: types.NetworkEVM, ChainID: evmChainID1.String()}, + {Network: types.NetworkEVM, ChainID: evmChainID2.String()}, }, expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, - expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: solanaChainID1}, - {Network: relay.Solana, ChainID: solanaChainID2}, + expectedSolanaRelayerIds: []types.RelayID{ + {Network: types.NetworkSolana, ChainID: solanaChainID1}, + {Network: types.NetworkSolana, ChainID: solanaChainID2}, }, expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, - expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: starknetChainID1}, - {Network: relay.StarkNet, ChainID: starknetChainID2}, + expectedStarknetRelayerIds: []types.RelayID{ + {Network: types.NetworkStarkNet, ChainID: starknetChainID1}, + {Network: types.NetworkStarkNet, ChainID: starknetChainID2}, }, expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, - expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: cosmosChainID1}, - {Network: relay.Cosmos, ChainID: cosmosChainID2}, + expectedCosmosRelayerIds: []types.RelayID{ + {Network: types.NetworkCosmos, ChainID: cosmosChainID1}, + {Network: types.NetworkCosmos, ChainID: cosmosChainID2}, }, - expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}, relay.Cosmos: {}, relay.Solana: {}, relay.StarkNet: {}}, + expectedRelayerNetworks: map[string]struct{}{types.NetworkEVM: {}, types.NetworkCosmos: {}, types.NetworkSolana: {}, types.NetworkStarkNet: {}}, }, } for _, tt := range tests { @@ -362,17 +362,17 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { assert.Equal(t, cnt, len(allNodeStats)) } - gotRelayerNetworks := make(map[relay.Network]struct{}) - for relayNetwork := range relay.SupportedRelays { + gotRelayerNetworks := make(map[string]struct{}) + for relayNetwork := range types.SupportedRelays { var expectedChainCnt, expectedNodeCnt int switch relayNetwork { - case relay.EVM: + case types.NetworkEVM: expectedChainCnt, expectedNodeCnt = tt.expectedEVMChainCnt, tt.expectedEVMNodeCnt - case relay.Cosmos: + case types.NetworkCosmos: expectedChainCnt, expectedNodeCnt = tt.expectedCosmosChainCnt, tt.expectedCosmosNodeCnt - case relay.Solana: + case types.NetworkSolana: expectedChainCnt, expectedNodeCnt = tt.expectedSolanaChainCnt, tt.expectedSolanaNodeCnt - case relay.StarkNet: + case types.NetworkStarkNet: expectedChainCnt, expectedNodeCnt = tt.expectedStarknetChainCnt, tt.expectedStarknetNodeCnt default: require.Fail(t, "untested relay network", relayNetwork) @@ -385,16 +385,16 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { } // check legacy chains for those that haven't migrated fully to the loop relayer interface - if relayNetwork == relay.EVM { - _, wantEVM := tt.expectedRelayerNetworks[relay.EVM] + if relayNetwork == types.NetworkEVM { + _, wantEVM := tt.expectedRelayerNetworks[types.NetworkEVM] if wantEVM { assert.Len(t, cr.LegacyEVMChains().Slice(), expectedChainCnt) } else { assert.Nil(t, cr.LegacyEVMChains()) } } - if relayNetwork == relay.Cosmos { - _, wantCosmos := tt.expectedRelayerNetworks[relay.Cosmos] + if relayNetwork == types.NetworkCosmos { + _, wantCosmos := tt.expectedRelayerNetworks[types.NetworkCosmos] if wantCosmos { assert.Len(t, cr.LegacyCosmosChains().Slice(), expectedChainCnt) } else { @@ -410,7 +410,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { } assert.EqualValues(t, gotRelayerNetworks, tt.expectedRelayerNetworks) - allRelayerIds := [][]relay.ID{ + allRelayerIds := [][]types.RelayID{ tt.expectedEVMRelayerIds, tt.expectedCosmosRelayerIds, tt.expectedSolanaRelayerIds, @@ -426,13 +426,13 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { assert.NoError(t, err) assert.Equal(t, wantId.ChainID, stat.ID) // check legacy chains for evm and cosmos - if wantId.Network == relay.EVM { + if wantId.Network == types.NetworkEVM { c, err := cr.LegacyEVMChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) assert.Equal(t, wantId.ChainID, c.ID().String()) } - if wantId.Network == relay.Cosmos { + if wantId.Network == types.NetworkCosmos { c, err := cr.LegacyCosmosChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) @@ -441,7 +441,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { } } - expectedMissing := relay.ID{Network: relay.Cosmos, ChainID: "not a chain id"} + expectedMissing := types.RelayID{Network: types.NetworkCosmos, ChainID: "not a chain id"} unwanted, err := cr.Get(expectedMissing) assert.Nil(t, unwanted) assert.ErrorIs(t, err, chainlink.ErrNoSuchRelayer) diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 2dd5e1eb68a..5902555f79c 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -9,6 +9,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" @@ -40,10 +41,10 @@ type EVMFactoryConfig struct { evmrelay.CSAETHKeystore } -func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (map[relay.ID]evmrelay.LoopRelayAdapter, error) { +func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (map[types.RelayID]evmrelay.LoopRelayAdapter, error) { // TODO impl EVM loop. For now always 'fallback' to an adapter and embedded chain - relayers := make(map[relay.ID]evmrelay.LoopRelayAdapter) + relayers := make(map[types.RelayID]evmrelay.LoopRelayAdapter) lggr := r.Logger.Named("EVM") @@ -60,7 +61,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m } legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) for _, ext := range evmRelayExtenders.Slice() { - relayID := relay.ID{Network: relay.EVM, ChainID: ext.Chain().ID().String()} + relayID := types.RelayID{Network: types.NetworkEVM, ChainID: ext.Chain().ID().String()} chain, err2 := legacyChains.Get(relayID.ChainID) if err2 != nil { return nil, err2 @@ -91,8 +92,8 @@ type SolanaFactoryConfig struct { solana.TOMLConfigs } -func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConfigs) (map[relay.ID]loop.Relayer, error) { - solanaRelayers := make(map[relay.ID]loop.Relayer) +func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) { + solanaRelayers := make(map[types.RelayID]loop.Relayer) var ( solLggr = r.Logger.Named("Solana") signer = &keystore.SolanaSigner{Solana: ks} @@ -102,7 +103,7 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConf // create one relayer per chain id for _, chainCfg := range chainCfgs { - relayID := relay.ID{Network: relay.Solana, ChainID: *chainCfg.ChainID} + relayID := types.RelayID{Network: types.NetworkSolana, ChainID: *chainCfg.ChainID} _, alreadyExists := unique[relayID.Name()] if alreadyExists { return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name()) @@ -166,8 +167,8 @@ type StarkNetFactoryConfig struct { // TODO BCF-2606 consider consolidating the driving logic with that of NewSolana above via generics // perhaps when we implement a Cosmos LOOP -func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOMLConfigs) (map[relay.ID]loop.Relayer, error) { - starknetRelayers := make(map[relay.ID]loop.Relayer) +func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) { + starknetRelayers := make(map[types.RelayID]loop.Relayer) var ( starkLggr = r.Logger.Named("StarkNet") @@ -177,7 +178,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML unique := make(map[string]struct{}) // create one relayer per chain id for _, chainCfg := range chainCfgs { - relayID := relay.ID{Network: relay.StarkNet, ChainID: *chainCfg.ChainID} + relayID := types.RelayID{Network: types.NetworkStarkNet, ChainID: *chainCfg.ChainID} _, alreadyExists := unique[relayID.Name()] if alreadyExists { return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name()) @@ -263,12 +264,12 @@ func (c CosmosFactoryConfig) Validate() error { return err } -func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[relay.ID]CosmosLoopRelayerChainer, error) { +func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[types.RelayID]CosmosLoopRelayerChainer, error) { err := config.Validate() if err != nil { return nil, fmt.Errorf("cannot create Cosmos relayer: %w", err) } - relayers := make(map[relay.ID]CosmosLoopRelayerChainer) + relayers := make(map[types.RelayID]CosmosLoopRelayerChainer) var ( cosmosLggr = r.Logger.Named("Cosmos") @@ -277,7 +278,7 @@ func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[relay.ID]Cos // create one relayer per chain id for _, chainCfg := range config.TOMLConfigs { - relayID := relay.ID{Network: relay.Cosmos, ChainID: *chainCfg.ChainID} + relayID := types.RelayID{Network: types.NetworkCosmos, ChainID: *chainCfg.ChainID} lggr := cosmosLggr.Named(relayID.ChainID) diff --git a/core/services/cron/cron_test.go b/core/services/cron/cron_test.go index 3ace0f3ceae..b31a06a9591 100644 --- a/core/services/cron/cron_test.go +++ b/core/services/cron/cron_test.go @@ -25,9 +25,9 @@ func TestCronV2Pipeline(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) lggr := logger.TestLogger(t) - orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + orm := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) jobORM := job.NewORM(db, orm, btORM, keyStore, lggr, cfg.Database()) diff --git a/core/services/cron/delegate.go b/core/services/cron/delegate.go index 05b5b36c00f..d8a1390103e 100644 --- a/core/services/cron/delegate.go +++ b/core/services/cron/delegate.go @@ -7,7 +7,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -29,10 +28,10 @@ func (d *Delegate) JobType() job.Type { return job.Cron } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec returns the scheduler to be used for running cron jobs func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index d6afc215fb9..33a0a7e73da 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -19,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -63,10 +63,10 @@ func (d *Delegate) JobType() job.Type { return job.DirectRequest } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec returns the log listener service for a direct request job func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { @@ -191,7 +191,7 @@ func (l *listener) Close() error { }) } -func (l *listener) HandleLog(lb log.Broadcast) { +func (l *listener) HandleLog(ctx context.Context, lb log.Broadcast) { log := lb.DecodedLog() if log == nil || reflect.ValueOf(log).IsNil() { l.logger.Error("HandleLog: ignoring nil value") @@ -374,7 +374,7 @@ func (l *listener) handleOracleRequest(ctx context.Context, request *operator_wr }, }) run := pipeline.NewRun(*l.job.PipelineSpec, vars) - _, err := l.pipelineRunner.Run(ctx, run, l.logger, true, func(tx pg.Queryer) error { + _, err := l.pipelineRunner.Run(ctx, run, l.logger, true, func(tx sqlutil.DataSource) error { l.markLogConsumed(ctx, lb) return nil }) @@ -407,7 +407,7 @@ func (l *listener) handleCancelOracleRequest(ctx context.Context, request *opera } func (l *listener) markLogConsumed(ctx context.Context, lb log.Broadcast) { - if err := l.logBroadcaster.MarkConsumed(ctx, lb); err != nil { + if err := l.logBroadcaster.MarkConsumed(ctx, nil, lb); err != nil { l.logger.Errorw("Unable to mark log consumed", "err", err, "log", lb.String()) } } diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index a7f2ba01315..08f38865bec 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -31,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipeline_mocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -44,7 +44,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, MailMon: mailMon, KeyStore: keyStore.Eth()}) @@ -85,10 +85,10 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, LogBroadcaster: broadcaster, MailMon: mailMon, KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) - orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + orm := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) jobORM := job.NewORM(db, orm, btORM, keyStore, lggr, cfg.Database()) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -159,28 +159,29 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }) log.On("DecodedLog").Return(&logOracleRequest) log.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) runBeganAwaiter := cltest.NewAwaiter() uni.runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything, mock.Anything). Return(false, nil). Run(func(args mock.Arguments) { runBeganAwaiter.ItHappened() - fn := args.Get(4).(func(pg.Queryer) error) + fn := args.Get(4).(func(source sqlutil.DataSource) error) require.NoError(t, fn(nil)) }).Once() - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) require.NotNil(t, uni.listener, "listener was nil; expected broadcaster.Register to have been called") // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(testutils.Context(t), uni.listener.JobID()) + drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) require.NoError(t, jErr) require.Equal(t, drJob.ID, uni.listener.JobID()) require.NotNil(t, drJob.DirectRequestSpec) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) runBeganAwaiter.AwaitOrFail(t, 5*time.Second) @@ -207,12 +208,13 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("DecodedLog").Return(&logOracleRequest).Maybe() log.On("String").Return("") log.On("EVMChainID").Return(*big.NewInt(0)) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Maybe() + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe() - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) @@ -224,7 +226,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Run(func(args mock.Arguments) { runBeganAwaiter.ItHappened() - fn := args.Get(4).(func(pg.Queryer) error) + fn := args.Get(4).(func(sqlutil.DataSource) error) require.NoError(t, fn(nil)) }).Once().Return(false, nil) @@ -241,7 +243,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log := log_mocks.NewBroadcast(t) lbAwaiter := cltest.NewAwaiter() uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) logCancelOracleRequest := operator_wrapper.OperatorCancelOracleRequest{RequestId: uni.spec.ExternalIDEncodeStringToTopic()} logAwaiter := cltest.NewAwaiter() @@ -251,10 +253,11 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }) log.On("String").Return("") - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) logAwaiter.AwaitOrFail(t) lbAwaiter.AwaitOrFail(t) @@ -279,12 +282,13 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("String").Return("") log.On("DecodedLog").Return(&logCancelOracleRequest) lbAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) lbAwaiter.AwaitOrFail(t) @@ -314,7 +318,7 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }) runLog.On("DecodedLog").Return(&logOracleRequest) runLog.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) cancelLog := log_mocks.NewBroadcast(t) @@ -328,9 +332,10 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }) cancelLog.On("DecodedLog").Return(&logCancelOracleRequest) cancelLog.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) timeout := 5 * time.Second @@ -346,11 +351,11 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { runCancelledAwaiter.ItHappened() } }).Once().Return(false, nil) - uni.listener.HandleLog(runLog) + uni.listener.HandleLog(ctx, runLog) runBeganAwaiter.AwaitOrFail(t, timeout) - uni.listener.HandleLog(cancelLog) + uni.listener.HandleLog(ctx, cancelLog) runCancelledAwaiter.AwaitOrFail(t, timeout) @@ -384,25 +389,26 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { }) log.On("DecodedLog").Return(&logOracleRequest) log.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) runBeganAwaiter := cltest.NewAwaiter() uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { runBeganAwaiter.ItHappened() - fn := args.Get(4).(func(pg.Queryer) error) + fn := args.Get(4).(func(sqlutil.DataSource) error) require.NoError(t, fn(nil)) }).Once().Return(false, nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(testutils.Context(t), uni.listener.JobID()) + drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) require.NoError(t, jErr) require.Equal(t, drJob.ID, uni.listener.JobID()) require.NotNil(t, drJob.DirectRequestSpec) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) runBeganAwaiter.AwaitOrFail(t, 5*time.Second) @@ -433,14 +439,15 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("DecodedLog").Return(&logOracleRequest) log.On("String").Return("") markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { markConsumedLogAwaiter.ItHappened() }).Return(nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) markConsumedLogAwaiter.AwaitOrFail(t, 5*time.Second) @@ -479,27 +486,28 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("DecodedLog").Return(&logOracleRequest) log.On("String").Return("") markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { markConsumedLogAwaiter.ItHappened() }).Return(nil) runBeganAwaiter := cltest.NewAwaiter() uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { runBeganAwaiter.ItHappened() - fn := args.Get(4).(func(pg.Queryer) error) + fn := args.Get(4).(func(sqlutil.DataSource) error) require.NoError(t, fn(nil)) }).Once().Return(false, nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(testutils.Context(t), uni.listener.JobID()) + drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) require.NoError(t, jErr) require.Equal(t, drJob.ID, uni.listener.JobID()) require.NotNil(t, drJob.DirectRequestSpec) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) runBeganAwaiter.AwaitOrFail(t, 5*time.Second) @@ -534,14 +542,15 @@ func TestDelegate_ServicesListenerHandleLog(t *testing.T) { log.On("DecodedLog").Return(&logOracleRequest) log.On("String").Return("") markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { markConsumedLogAwaiter.ItHappened() }).Return(nil) - err := uni.service.Start(testutils.Context(t)) + ctx := testutils.Context(t) + err := uni.service.Start(ctx) require.NoError(t, err) - uni.listener.HandleLog(log) + uni.listener.HandleLog(ctx, log) markConsumedLogAwaiter.AwaitOrFail(t, 5*time.Second) diff --git a/core/services/feeds/config.go b/core/services/feeds/config.go index 141e4910960..e2ec889b23b 100644 --- a/core/services/feeds/config.go +++ b/core/services/feeds/config.go @@ -4,8 +4,14 @@ import ( "time" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" ) +type GeneralConfig interface { + OCR() coreconfig.OCR + Insecure() coreconfig.Insecure +} + type JobConfig interface { DefaultHTTPTimeout() commonconfig.Duration } @@ -25,5 +31,7 @@ type OCR2Config interface { ContractPollInterval() time.Duration ContractTransmitterTransmitTimeout() time.Duration DatabaseTimeout() time.Duration + DefaultTransactionQueueDepth() uint32 + SimulateTransactions() bool TraceLogging() bool } diff --git a/core/services/feeds/mocks/connections_manager.go b/core/services/feeds/mocks/connections_manager.go index 5bdc5087108..06cb0eeb5aa 100644 --- a/core/services/feeds/mocks/connections_manager.go +++ b/core/services/feeds/mocks/connections_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/feeds_manager_client.go b/core/services/feeds/mocks/feeds_manager_client.go index f07200cc8fd..71c8786da3e 100644 --- a/core/services/feeds/mocks/feeds_manager_client.go +++ b/core/services/feeds/mocks/feeds_manager_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index 73bc4c4d4a0..f84d80a6eb1 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index d8bc88c8159..05ede181f44 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 23f40b9d55c..3a0a17c99e0 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "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/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -1647,18 +1648,19 @@ func createFeedsManager(t *testing.T, orm feeds.ORM) int64 { func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { t.Helper() + ctx := testutils.Context(t) var ( config = configtest.NewGeneralConfig(t, nil) - keyStore = cltest.NewKeyStore(t, db, config.Database()) + keyStore = cltest.NewKeyStore(t, db) lggr = logger.TestLogger(t) - pipelineORM = pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM = pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgeORM = bridges.NewORM(db) relayExtenders = evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) ) orm := job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) defer func() { assert.NoError(t, orm.Close()) }() @@ -1667,7 +1669,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index aa6ccdb39d7..8c4ea7a36bf 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -111,6 +111,7 @@ type service struct { ocr1KeyStore keystore.OCR ocr2KeyStore keystore.OCR2 jobSpawner job.Spawner + gCfg GeneralConfig insecureCfg InsecureConfig jobCfg JobConfig ocrCfg OCRConfig @@ -129,6 +130,7 @@ func NewService( db *sqlx.DB, jobSpawner job.Spawner, keyStore keystore.Master, + gCfg GeneralConfig, insecureCfg InsecureConfig, jobCfg JobConfig, ocrCfg OCRConfig, @@ -149,6 +151,7 @@ func NewService( csaKeyStore: keyStore.CSA(), ocr1KeyStore: keyStore.OCR(), ocr2KeyStore: keyStore.OCR2(), + gCfg: gCfg, insecureCfg: insecureCfg, jobCfg: jobCfg, ocrCfg: ocrCfg, @@ -1137,7 +1140,7 @@ func (s *service) generateJob(ctx context.Context, spec string) (*job.Job, error if !s.ocrCfg.Enabled() { return nil, ErrOCRDisabled } - js, err = ocr.ValidatedOracleSpecToml(s.legacyChains, spec) + js, err = ocr.ValidatedOracleSpecToml(s.gCfg, s.legacyChains, spec) case job.OffchainReporting2: if !s.ocr2cfg.Enabled() { return nil, ErrOCR2Disabled @@ -1191,7 +1194,7 @@ func (s *service) newChainConfigMsg(cfg ChainConfig) (*pb.ChainConfig, error) { }, nil } -// newFMConfigMsg generates a FMConfig protobuf message. Flux Monitor does not +// newFluxMonitorConfigMsg generates a FMConfig protobuf message. Flux Monitor does not // have any configuration but this is here for consistency. func (*service) newFluxMonitorConfigMsg(cfg FluxMonitorConfig) *pb.FluxMonitorConfig { return &pb.FluxMonitorConfig{Enabled: cfg.Enabled} diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 0dc07b57d43..f83a98986e2 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -177,8 +177,7 @@ func setupTestServiceCfg(t *testing.T, overrideCfg func(c *chainlink.Config, s * db := pgtest.NewSqlxDB(t) gcfg := configtest.NewGeneralConfig(t, overrideCfg) keyStore := new(ksmocks.Master) - scopedConfig := evmtest.NewChainScopedConfig(t, gcfg) - ethKeyStore := cltest.NewKeyStore(t, db, gcfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: gcfg, HeadTracker: headtracker.NullTracker, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -187,7 +186,7 @@ func setupTestServiceCfg(t *testing.T, overrideCfg func(c *chainlink.Config, s * keyStore.On("P2P").Return(p2pKeystore) keyStore.On("OCR").Return(ocr1Keystore) keyStore.On("OCR2").Return(ocr2Keystore) - svc := feeds.NewService(orm, jobORM, db, spawner, keyStore, scopedConfig.Insecure(), scopedConfig.JobPipeline(), scopedConfig.OCR(), scopedConfig.OCR2(), scopedConfig.Database(), legacyChains, lggr, "1.0.0", nil) + svc := feeds.NewService(orm, jobORM, db, spawner, keyStore, gcfg, gcfg.Insecure(), gcfg.JobPipeline(), gcfg.OCR(), gcfg.OCR2(), gcfg.Database(), legacyChains, lggr, "1.0.0", nil) svc.SetConnectionsManager(connMgr) return &TestService{ diff --git a/core/services/fluxmonitorv2/contract_submitter_test.go b/core/services/fluxmonitorv2/contract_submitter_test.go index 238cf96e033..7dfd92e5acd 100644 --- a/core/services/fluxmonitorv2/contract_submitter_test.go +++ b/core/services/fluxmonitorv2/contract_submitter_test.go @@ -15,6 +15,7 @@ import ( ) func TestFluxAggregatorContractSubmitter_Submit(t *testing.T) { + t.Parallel() var ( fluxAggregator = mocks.NewFluxAggregator(t) orm = fmmocks.NewORM(t) diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index 1e2eba8d000..b7b0df77cc4 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -10,15 +10,21 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) +type DelegateConfig interface { + FluxMonitor() config.FluxMonitor + JobPipeline() config.JobPipeline +} + // Delegate represents a Flux Monitor delegate type Delegate struct { + cfg DelegateConfig db *sqlx.DB ethKeyStore keystore.Eth jobORM job.ORM @@ -32,6 +38,7 @@ var _ job.Delegate = (*Delegate)(nil) // NewDelegate constructs a new delegate func NewDelegate( + cfg DelegateConfig, ethKeyStore keystore.Eth, jobORM job.ORM, pipelineORM pipeline.ORM, @@ -41,6 +48,7 @@ func NewDelegate( lggr logger.Logger, ) *Delegate { return &Delegate{ + cfg: cfg, db: db, ethKeyStore: ethKeyStore, jobORM: jobORM, @@ -56,10 +64,10 @@ func (d *Delegate) JobType() job.Type { return job.FluxMonitor } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec returns the flux monitor service for the job spec func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { @@ -70,17 +78,16 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] if err != nil { return nil, err } - cfg := chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(jb.ExternalJobID, cfg.FluxMonitor().DefaultTransactionQueueDepth(), cfg.Database().DefaultQueryTimeout()) + strategy := txmgrcommon.NewQueueingTxStrategy(jb.ExternalJobID, d.cfg.FluxMonitor().DefaultTransactionQueueDepth()) var checker txmgr.TransmitCheckerSpec - if chain.Config().FluxMonitor().SimulateTransactions() { + if d.cfg.FluxMonitor().SimulateTransactions() { checker.CheckerType = txmgr.TransmitCheckerTypeSimulate } fm, err := NewFromJobSpec( jb, d.db, - NewORM(d.db, d.lggr, chain.Config().Database(), chain.TxManager(), strategy, checker), + NewORM(d.db, d.lggr, chain.TxManager(), strategy, checker), d.jobORM, d.pipelineORM, NewKeyStore(d.ethKeyStore), @@ -89,10 +96,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] d.pipelineRunner, chain.Config().EVM(), chain.Config().EVM().GasEstimator(), - chain.Config().EVM().Transactions(), - chain.Config().FluxMonitor(), - chain.Config().JobPipeline(), - chain.Config().Database(), + d.cfg.JobPipeline(), d.lggr, ) if err != nil { diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 73034faa3ce..5eebb319030 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -16,6 +16,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/recovery" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2/promfm" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -64,7 +64,7 @@ type FluxMonitor struct { jobSpec job.Job spec pipeline.Spec runner pipeline.Runner - q pg.Q + ds sqlutil.DataSource orm ORM jobORM job.ORM pipelineORM pipeline.ORM @@ -93,7 +93,7 @@ func NewFluxMonitor( pipelineRunner pipeline.Runner, jobSpec job.Job, spec pipeline.Spec, - q pg.Q, + ds sqlutil.DataSource, orm ORM, jobORM job.ORM, pipelineORM pipeline.ORM, @@ -111,7 +111,7 @@ func NewFluxMonitor( chainID *big.Int, ) (*FluxMonitor, error) { fm := &FluxMonitor{ - q: q, + ds: ds, runner: pipelineRunner, jobSpec: jobSpec, spec: spec, @@ -159,10 +159,7 @@ func NewFromJobSpec( pipelineRunner pipeline.Runner, cfg Config, fcfg EvmFeeConfig, - ecfg EvmTransactionsConfig, - fmcfg FluxMonitorConfig, jcfg JobPipelineConfig, - dbCfg pg.QConfig, lggr logger.Logger, ) (*FluxMonitor, error) { fmSpec := jobSpec.FluxMonitorSpec @@ -253,7 +250,7 @@ func NewFromJobSpec( pipelineRunner, jobSpec, *jobSpec.PipelineSpec, - pg.NewQ(db, lggr, dbCfg), + db, orm, jobORM, pipelineORM, @@ -325,7 +322,7 @@ func (fm *FluxMonitor) Close() error { func (fm *FluxMonitor) JobID() int32 { return fm.spec.JobID } // HandleLog processes the contract logs -func (fm *FluxMonitor) HandleLog(broadcast log.Broadcast) { +func (fm *FluxMonitor) HandleLog(ctx context.Context, broadcast log.Broadcast) { log := broadcast.DecodedLog() if log == nil || reflect.ValueOf(log).IsNil() { fm.logger.Panic("HandleLog: failed to handle log of type nil") @@ -509,15 +506,16 @@ func (fm *FluxMonitor) SetOracleAddress() error { } func (fm *FluxMonitor) processLogs() { - for !fm.backlog.Empty() { + ctx, cancel := fm.chStop.NewCtx() + defer cancel() + + for ctx.Err() == nil && !fm.backlog.Empty() { broadcast := fm.backlog.Take() - fm.processBroadcast(broadcast) + fm.processBroadcast(ctx, broadcast) } } -func (fm *FluxMonitor) processBroadcast(broadcast log.Broadcast) { - ctx, cancel := fm.chStop.NewCtx() - defer cancel() +func (fm *FluxMonitor) processBroadcast(ctx context.Context, broadcast log.Broadcast) { // If the log is a duplicate of one we've seen before, ignore it (this // happens because of the LogBroadcaster's backfilling behavior). consumed, err := fm.logBroadcaster.WasAlreadyConsumed(ctx, broadcast) @@ -553,7 +551,7 @@ func (fm *FluxMonitor) processBroadcast(broadcast log.Broadcast) { } func (fm *FluxMonitor) markLogAsConsumed(ctx context.Context, broadcast log.Broadcast, decodedLog interface{}, started time.Time) { - if err := fm.logBroadcaster.MarkConsumed(ctx, broadcast); err != nil { + if err := fm.logBroadcaster.MarkConsumed(ctx, nil, broadcast); err != nil { fm.logger.Errorw("Failed to mark log as consumed", "err", err, "logType", fmt.Sprintf("%T", decodedLog), "log", broadcast.String(), "elapsed", time.Since(started)) } @@ -608,7 +606,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr var markConsumed = true defer func() { if markConsumed { - if err := fm.logBroadcaster.MarkConsumed(ctx, lb); err != nil { + if err := fm.logBroadcaster.MarkConsumed(ctx, nil, lb); err != nil { fm.logger.Errorw("Failed to mark log consumed", "err", err, "log", lb.String()) } } @@ -665,13 +663,13 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr // We always want to reset the idle timer upon receiving a NewRound log, so we do it before any `return` statements. fm.pollManager.ResetIdleTimer(log.StartedAt.Uint64()) - mostRecentRoundID, err := fm.orm.MostRecentFluxMonitorRoundID(fm.contractAddress) + mostRecentRoundID, err := fm.orm.MostRecentFluxMonitorRoundID(ctx, fm.contractAddress) if err != nil && !errors.Is(err, sql.ErrNoRows) { newRoundLogger.Errorf("error fetching Flux Monitor most recent round ID from DB: %v", err) return } - roundStats, jobRunStatus, err := fm.statsAndStatusForRound(logRoundID, 1) + roundStats, jobRunStatus, err := fm.statsAndStatusForRound(ctx, logRoundID, 1) if err != nil { newRoundLogger.Errorf("error determining round stats / run status for round: %v", err) return @@ -680,14 +678,14 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr if logRoundID < mostRecentRoundID && roundStats.NumNewRoundLogs > 0 { newRoundLogger.Debugf("Received an older round log (and number of previously received NewRound logs is: %v) - "+ "a possible reorg, hence deleting round ids from %v to %v", roundStats.NumNewRoundLogs, logRoundID, mostRecentRoundID) - err = fm.orm.DeleteFluxMonitorRoundsBackThrough(fm.contractAddress, logRoundID) + err = fm.orm.DeleteFluxMonitorRoundsBackThrough(ctx, fm.contractAddress, logRoundID) if err != nil { newRoundLogger.Errorf("error deleting reorged Flux Monitor rounds from DB: %v", err) return } // as all newer stats were deleted, at this point a new round stats entry will be created - roundStats, err = fm.orm.FindOrCreateFluxMonitorRoundStats(fm.contractAddress, logRoundID, 1) + roundStats, err = fm.orm.FindOrCreateFluxMonitorRoundStats(ctx, fm.contractAddress, logRoundID, 1) if err != nil { newRoundLogger.Errorf("error determining subsequent round stats for round: %v", err) return @@ -771,7 +769,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr return } - if !fm.isValidSubmission(newRoundLogger, answer, started) { + if !fm.isValidSubmission(ctx, newRoundLogger, answer, started) { return } @@ -779,14 +777,14 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr newRoundLogger.Error("roundState.PaymentAmount shouldn't be nil") } - err = fm.q.Transaction(func(tx pg.Queryer) error { - if err2 := fm.runner.InsertFinishedRun(run, false, pg.WithQueryer(tx)); err2 != nil { + err = fm.Transact(ctx, func(tx sqlutil.DataSource) error { + if err2 := fm.runner.InsertFinishedRun(ctx, tx, run, false); err2 != nil { return err2 } if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, &log); err2 != nil { return err2 } - return fm.logBroadcaster.MarkConsumed(ctx, lb) + return fm.logBroadcaster.MarkConsumed(ctx, tx, lb) }) // Either the tx failed and we want to reprocess the log, or it succeeded and already marked it consumed markConsumed = false @@ -796,6 +794,10 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr } } +func (fm *FluxMonitor) Transact(ctx context.Context, fn func(sqlutil.DataSource) error) error { + return sqlutil.TransactDataSource(ctx, fm.ds, nil, fn) +} + var ( // ErrNotEligible defines when the round is not eligible for submission ErrNotEligible = errors.New("not eligible to submit") @@ -832,7 +834,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker var markConsumed = true defer func() { if markConsumed && broadcast != nil { - if err := fm.logBroadcaster.MarkConsumed(ctx, broadcast); err != nil { + if err := fm.logBroadcaster.MarkConsumed(ctx, nil, broadcast); err != nil { l.Errorw("Failed to mark log consumed", "err", err, "log", broadcast.String()) } } @@ -863,8 +865,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker roundState, err := fm.roundState(0) if err != nil { l.Errorw("unable to determine eligibility to submit from FluxAggregator contract", "err", err) - fm.jobORM.TryRecordError( - fm.spec.JobID, + fm.jobORM.TryRecordError(fm.spec.JobID, "Unable to call roundState method on provided contract. Check contract address.", ) @@ -884,8 +885,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker roundStateNew, err2 := fm.roundState(roundState.RoundId) if err2 != nil { l.Errorw("unable to determine eligibility to submit from FluxAggregator contract", "err", err2) - fm.jobORM.TryRecordError( - fm.spec.JobID, + fm.jobORM.TryRecordError(fm.spec.JobID, "Unable to call roundState method on provided contract. Check contract address.", ) @@ -909,7 +909,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker } }() - roundStats, jobRunStatus, err := fm.statsAndStatusForRound(roundState.RoundId, 0) + roundStats, jobRunStatus, err := fm.statsAndStatusForRound(ctx, roundState.RoundId, 0) if err != nil { l.Errorw("error determining round stats / run status for round", "err", err) @@ -977,7 +977,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker return } - if !fm.isValidSubmission(l, answer, started) { + if !fm.isValidSubmission(ctx, l, answer, started) { return } @@ -1005,8 +1005,8 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker l.Error("roundState.PaymentAmount shouldn't be nil") } - err = fm.q.Transaction(func(tx pg.Queryer) error { - if err2 := fm.runner.InsertFinishedRun(run, true, pg.WithQueryer(tx)); err2 != nil { + err = fm.Transact(ctx, func(tx sqlutil.DataSource) error { + if err2 := fm.runner.InsertFinishedRun(ctx, tx, run, true); err2 != nil { return err2 } if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, nil); err2 != nil { @@ -1014,7 +1014,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker } if broadcast != nil { // In the case of a flag lowered, the pollEligible call is triggered by a log. - return fm.logBroadcaster.MarkConsumed(ctx, broadcast) + return fm.logBroadcaster.MarkConsumed(ctx, tx, broadcast) } return nil }) @@ -1031,7 +1031,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker // If the answer is outside the allowable range, log an error and don't submit. // to avoid an onchain reversion. -func (fm *FluxMonitor) isValidSubmission(l logger.Logger, answer decimal.Decimal, started time.Time) bool { +func (fm *FluxMonitor) isValidSubmission(ctx context.Context, l logger.Logger, answer decimal.Decimal, started time.Time) bool { if fm.submissionChecker.IsValid(answer) { return true } @@ -1085,7 +1085,7 @@ func (fm *FluxMonitor) initialRoundState() flux_aggregator_wrapper.OracleRoundSt return latestRoundState } -func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx pg.Queryer, runID int64, answer decimal.Decimal, roundID uint32, log *flux_aggregator_wrapper.FluxAggregatorNewRound) error { +func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx sqlutil.DataSource, runID int64, answer decimal.Decimal, roundID uint32, log *flux_aggregator_wrapper.FluxAggregatorNewRound) error { // Use pipeline run ID to generate globally unique key that can correlate this run to a Tx idempotencyKey := fmt.Sprintf("fluxmonitor-%d", runID) // Submit the Eth Tx @@ -1105,12 +1105,12 @@ func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx pg.Queryer numLogs = 1 } // Update the flux monitor round stats - err = fm.orm.UpdateFluxMonitorRoundStats( + err = fm.orm.WithDataSource(tx).UpdateFluxMonitorRoundStats( + ctx, fm.contractAddress, roundID, runID, numLogs, - pg.WithQueryer(tx), ) if err != nil { fm.logger.Errorw( @@ -1124,8 +1124,8 @@ func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx pg.Queryer return nil } -func (fm *FluxMonitor) statsAndStatusForRound(roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, pipeline.RunStatus, error) { - roundStats, err := fm.orm.FindOrCreateFluxMonitorRoundStats(fm.contractAddress, roundID, newRoundLogs) +func (fm *FluxMonitor) statsAndStatusForRound(ctx context.Context, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, pipeline.RunStatus, error) { + roundStats, err := fm.orm.FindOrCreateFluxMonitorRoundStats(ctx, fm.contractAddress, roundID, newRoundLogs) if err != nil { return FluxMonitorRoundStatsV2{}, pipeline.RunStatusUnknown, err } @@ -1133,7 +1133,7 @@ func (fm *FluxMonitor) statsAndStatusForRound(roundID uint32, newRoundLogs uint) // JobRun will not exist if this is the first time responding to this round var run pipeline.Run if roundStats.PipelineRunID.Valid { - run, err = fm.pipelineORM.FindRun(roundStats.PipelineRunID.Int64) + run, err = fm.pipelineORM.FindRun(ctx, roundStats.PipelineRunID.Int64) if err != nil { return FluxMonitorRoundStatsV2{}, pipeline.RunStatusUnknown, err } diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index e4db716bbbb..2ac424bceab 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -31,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/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" corenull "github.com/smartcontractkit/chainlink/v2/core/null" @@ -40,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" jobmocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" ) @@ -53,8 +52,8 @@ var ( type answerSet struct{ latestAnswer, polledAnswer int64 } -func newORM(t *testing.T, db *sqlx.DB, cfg pg.QConfig, txm txmgr.TxManager) fluxmonitorv2.ORM { - return fluxmonitorv2.NewORM(db, logger.TestLogger(t), cfg, txm, txmgrcommon.NewSendEveryStrategy(), txmgr.TransmitCheckerSpec{}) +func newORM(t *testing.T, db *sqlx.DB, txm txmgr.TxManager) fluxmonitorv2.ORM { + return fluxmonitorv2.NewORM(db, logger.TestLogger(t), txm, txmgrcommon.NewSendEveryStrategy(), txmgr.TransmitCheckerSpec{}) } var ( @@ -149,7 +148,7 @@ type setupOptions struct { // setup sets up a Flux Monitor for testing, allowing the test to provide // functional options to configure the setup -func setup(t *testing.T, db *sqlx.DB, optionFns ...func(*setupOptions)) (*fluxmonitorv2.FluxMonitor, *testMocks) { +func setup(t *testing.T, ds sqlutil.DataSource, optionFns ...func(*setupOptions)) (*fluxmonitorv2.FluxMonitor, *testMocks) { t.Helper() testutils.SkipShort(t, "long test") @@ -190,7 +189,7 @@ func setup(t *testing.T, db *sqlx.DB, optionFns ...func(*setupOptions)) (*fluxmo tm.pipelineRunner, job.Job{}, pipelineSpec, - pg.NewQ(db, lggr, pgtest.NewQConfig(true)), + ds, options.orm, tm.jobORM, tm.pipelineORM, @@ -276,7 +275,7 @@ func withORM(orm fluxmonitorv2.ORM) func(*setupOptions) { // setupStoreWithKey setups a new store and adds a key to the keystore func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr @@ -284,14 +283,15 @@ func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { // setupStoreWithKey setups a new store and adds a key to the keystore func setupFullDBWithKey(t *testing.T) (*sqlx.DB, common.Address) { - cfg, db := heavyweight.FullTestDBV2(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + _, db := heavyweight.FullTestDBV2(t, nil) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr } func TestFluxMonitor_PollIfEligible(t *testing.T) { + t.Parallel() testCases := []struct { name string eligible bool @@ -386,7 +386,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { } tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(reportableRoundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(reportableRoundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: reportableRoundID, @@ -395,12 +395,12 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { }, nil) tm.pipelineORM. - On("FindRun", run.ID). + On("FindRun", mock.Anything, run.ID). Return(run, nil) } else { if tc.connected { tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(reportableRoundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(reportableRoundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: reportableRoundID, @@ -469,7 +469,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { tm.pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(2).(*pipeline.Run).ID = 1 }). Once() tm.contractSubmitter. @@ -479,13 +479,14 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(reportableRoundID), int64(1), mock.Anything, - mock.Anything, ). Return(nil) + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) } oracles := []common.Address{nodeAddr, testutils.NewAddress()} @@ -499,6 +500,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { // If the roundState method is unable to communicate with the contract (possibly due to // incorrect address) then the pollIfEligible method should create a JobErr record func TestFluxMonitor_PollIfEligible_Creates_JobErr(t *testing.T) { + t.Parallel() db, nodeAddr := setupStoreWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} @@ -529,6 +531,7 @@ func TestFluxMonitor_PollIfEligible_Creates_JobErr(t *testing.T) { } func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { + t.Parallel() db, nodeAddr := setupStoreWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} @@ -560,6 +563,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { logsAwaiter := cltest.NewAwaiter() tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) tm.fluxAggregator.On("Address").Return(common.Address{}) tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Maybe() @@ -573,19 +577,18 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(3)).Return(makeRoundStateForRoundID(3), nil).Once() tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(4)).Return(makeRoundStateForRoundID(4), nil).Once() tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - // tm.fluxAggregator.On("Address").Return(contractAddress, nil) tm.logBroadcaster.On("Register", fm, mock.Anything).Return(func() {}) tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(1), nil) - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(3), nil) - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(4), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(1), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(3), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(4), nil) // Round 1 run := &pipeline.Run{ID: 1} tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(1), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 1, @@ -605,7 +608,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(2).(*pipeline.Run).ID = 1 }).Once() tm.contractSubmitter. On("Submit", mock.Anything, big.NewInt(1), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). @@ -614,18 +617,18 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(1), mock.AnythingOfType("int64"), //int64(1), mock.Anything, - mock.Anything, ). Return(nil).Once() // Round 3 run = &pipeline.Run{ID: 2} tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(3), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(3), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 3, @@ -645,7 +648,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 2 + args.Get(2).(*pipeline.Run).ID = 2 }).Once() tm.contractSubmitter. On("Submit", mock.Anything, big.NewInt(3), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). @@ -653,18 +656,18 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { Once() tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(3), mock.AnythingOfType("int64"), //int64(2), mock.Anything, - mock.Anything, ). Return(nil).Once() // Round 4 run = &pipeline.Run{ID: 3} tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(4), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(4), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 3, @@ -684,7 +687,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 3 + args.Get(2).(*pipeline.Run).ID = 3 }).Once() tm.contractSubmitter. On("Submit", mock.Anything, big.NewInt(4), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). @@ -692,11 +695,11 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { Once() tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(4), mock.AnythingOfType("int64"), //int64(3), mock.Anything, - mock.Anything, ). Return(nil). Once(). @@ -711,23 +714,24 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorNewRound{RoundId: big.NewInt(int64(i)), StartedAt: big.NewInt(0)}) logBroadcast.On("String").Maybe().Return("") tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) logBroadcasts = append(logBroadcasts, logBroadcast) } - - fm.HandleLog(logBroadcasts[0]) // Get the checker to start processing a log so we can freeze it + ctx := testutils.Context(t) + fm.HandleLog(ctx, logBroadcasts[0]) // Get the checker to start processing a log so we can freeze it readyToFillQueue.AwaitOrFail(t) - fm.HandleLog(logBroadcasts[1]) // This log is evicted from the priority queue - fm.HandleLog(logBroadcasts[2]) - fm.HandleLog(logBroadcasts[3]) + fm.HandleLog(ctx, logBroadcasts[1]) // This log is evicted from the priority queue + fm.HandleLog(ctx, logBroadcasts[2]) + fm.HandleLog(ctx, logBroadcasts[3]) logsAwaiter.ItHappened() readyToAssert.AwaitOrFail(t) } func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { + t.Parallel() g := gomega.NewWithT(t) testCases := []struct { @@ -749,7 +753,7 @@ func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { t.Parallel() var ( - orm = newORM(t, db, pgtest.NewQConfig(true), nil) + orm = newORM(t, db, nil) ) fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(tc.idleTimerDisabled), setIdleTimerPeriod(tc.idleDuration), withORM(orm)) @@ -795,8 +799,8 @@ func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { tm.logBroadcast.On("DecodedLog").Return(&decodedLog) tm.logBroadcast.On("String").Maybe().Return("") tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) - fm.HandleLog(tm.logBroadcast) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) + fm.HandleLog(testutils.Context(t), tm.logBroadcast) g.Eventually(chBlock).Should(gomega.BeClosed()) @@ -856,7 +860,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { pollOccured <- struct{}{} }) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(1), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 1, @@ -873,7 +877,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { // Finds an existing run created by the initial poll tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(1), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -881,7 +885,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { NumSubmissions: 1, }, nil).Once() finishedAt := time.Now() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{ + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ FinishedAt: null.TimeFrom(finishedAt), }, nil) @@ -893,7 +897,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { pollOccured <- struct{}{} }) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(2), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(2), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 2, @@ -904,6 +908,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { } func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { + t.Parallel() db, nodeAddr := setupFullDBWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} @@ -950,7 +955,7 @@ func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { pollOccured <- struct{}{} }) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, roundOne, mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundOne, mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 1, @@ -970,7 +975,7 @@ func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { // Finds an error run, so that retry ticker will be kicked off tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, roundOne, mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundOne, mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -978,7 +983,7 @@ func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { NumSubmissions: 1, }, nil).Once() finishedAt := time.Now() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{ + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ FinishedAt: null.TimeFrom(finishedAt), FatalErrors: []null.String{null.StringFrom("an error to start retry ticker")}, }, nil) @@ -997,7 +1002,7 @@ func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 2, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: 0} tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, roundZero).Return(roundState2, nil).Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, roundTwo, mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundTwo, mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 2, @@ -1054,7 +1059,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1, nil).Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(1), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 1, @@ -1072,7 +1077,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { }) // Finds an existing run created by the initial poll tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(1), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -1080,7 +1085,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { NumSubmissions: 1, }, nil).Once() finishedAt := time.Now() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{ + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ FinishedAt: null.TimeFrom(finishedAt), }, nil) @@ -1092,7 +1097,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { idleDurationOccured <- struct{}{} }) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(2), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(2), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 2, @@ -1107,7 +1112,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { idleDurationOccured <- struct{}{} }) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(3), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(3), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: 3, @@ -1118,7 +1123,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Once() tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}) tm.logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Once() + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() fm.ExportedBacklog().Add(fluxmonitorv2.PriorityNewRoundLog, tm.logBroadcast) fm.ExportedProcessLogs() @@ -1133,7 +1138,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { var ( oracles = []common.Address{nodeAddr, testutils.NewAddress()} - orm = newORM(t, db, pgtest.NewQConfig(true), nil) + orm = newORM(t, db, nil) ) fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) @@ -1173,6 +1178,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { } func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) { + t.Parallel() g := gomega.NewWithT(t) db, nodeAddr := setupStoreWithKey(t) @@ -1193,10 +1199,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) t.Run(test.name, func(t *testing.T) { t.Parallel() - cfg := configtest.NewTestGeneralConfig(t) - var ( - orm = newORM(t, db, cfg.Database(), nil) - ) + orm := newORM(t, db, nil) fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) @@ -1237,6 +1240,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) } func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { + t.Parallel() g := gomega.NewWithT(t) db, nodeAddr := setupStoreWithKey(t) @@ -1260,11 +1264,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - cfg := configtest.NewTestGeneralConfig(t) - - var ( - orm = newORM(t, db, cfg.Database(), nil) - ) + orm := newORM(t, db, nil) fm, tm := setup(t, db, @@ -1323,11 +1323,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { g := gomega.NewWithT(t) db, nodeAddr := setupStoreWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} - cfg := configtest.NewTestGeneralConfig(t) - - var ( - orm = newORM(t, db, cfg.Database(), nil) - ) + orm := newORM(t, db, nil) fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) @@ -1381,14 +1377,14 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { servicetest.Run(t, fm) tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorNewRound{ RoundId: big.NewInt(0), StartedAt: big.NewInt(time.Now().UTC().Unix()), }) tm.logBroadcast.On("String").Maybe().Return("") // To mark it consumed, we need to be eligible to submit. - fm.HandleLog(tm.logBroadcast) + fm.HandleLog(testutils.Context(t), tm.logBroadcast) g.Eventually(chRoundState1).Should(gomega.BeClosed()) g.Eventually(chRoundState2).Should(gomega.BeClosed()) @@ -1409,7 +1405,7 @@ func TestFluxMonitor_ConsumeLogBroadcast(t *testing.T) { tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Once() tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}) tm.logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Once() + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() fm.ExportedBacklog().Add(fluxmonitorv2.PriorityNewRoundLog, tm.logBroadcast) fm.ExportedProcessLogs() @@ -1444,6 +1440,7 @@ func TestFluxMonitor_ConsumeLogBroadcast_Error(t *testing.T) { } func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { + t.Parallel() t.Run("when NewRound log arrives, then poll ticker fires", func(t *testing.T) { db, nodeAddr := setupStoreWithKey(t) oracles := []common.Address{nodeAddr, testutils.NewAddress()} @@ -1468,11 +1465,12 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) // Mocks initiated by the New Round log - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(roundID), nil).Once() + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil).Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(roundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: roundID, @@ -1492,17 +1490,17 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(2).(*pipeline.Run).ID = 1 }) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Once() + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(roundID), int64(1), uint(1), - mock.Anything, ). Return(nil) @@ -1545,7 +1543,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(roundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -1554,7 +1552,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { }, nil).Once() now := time.Now() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{ + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ FinishedAt: null.TimeFrom(now), }, nil) @@ -1583,6 +1581,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { run := &pipeline.Run{ID: 1} tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) // First, force the node to try to poll, which should result in a submission tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ @@ -1600,7 +1599,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { }, nil). Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(roundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: roundID, @@ -1620,16 +1619,16 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(2).(*pipeline.Run).ID = 1 }) tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(roundID), int64(1), uint(0), - mock.Anything, ). Return(nil). Once() @@ -1639,18 +1638,18 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { fm.ExportedPollIfEligible(0, 0) // Now fire off the NewRound log and ensure it does not respond this time - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(roundID), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(roundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, RoundID: roundID, NumSubmissions: 1, }, nil).Once() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{}, nil) + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ RoundId: big.NewInt(roundID), StartedAt: big.NewInt(0), @@ -1679,6 +1678,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { run := &pipeline.Run{ID: 1} tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) // First, force the node to try to poll, which should result in a submission tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ @@ -1696,7 +1696,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { }, nil). Once() tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(roundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ Aggregator: contractAddress, RoundID: roundID, @@ -1716,16 +1716,16 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(2).(*pipeline.Run).ID = 1 }) tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(roundID), int64(1), uint(0), - mock.Anything, ). Return(nil). Once() @@ -1735,27 +1735,27 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { fm.ExportedPollIfEligible(0, 0) // Now fire off the NewRound log and ensure it does not respond this time - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(roundID), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(olderRoundID), mock.Anything). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, RoundID: olderRoundID, NumSubmissions: 1, }, nil).Once() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{}, nil) + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ RoundId: big.NewInt(olderRoundID), StartedAt: big.NewInt(0), }, log.NewLogBroadcast(types.Log{}, cltest.FixtureChainID, nil)) // Simulate a reorg - fire the same NewRound log again, which should result in a submission this time - tm.orm.On("MostRecentFluxMonitorRoundID", contractAddress).Return(uint32(roundID), nil) + tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(olderRoundID), uint(1)). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), uint(1)). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -1763,14 +1763,14 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { NumSubmissions: 1, NumNewRoundLogs: 1, }, nil).Once() - tm.pipelineORM.On("FindRun", int64(1)).Return(pipeline.Run{}, nil) + tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) // all newer round stats should be deleted - tm.orm.On("DeleteFluxMonitorRoundsBackThrough", contractAddress, uint32(olderRoundID)).Return(nil) + tm.orm.On("DeleteFluxMonitorRoundsBackThrough", mock.Anything, contractAddress, uint32(olderRoundID)).Return(nil) // then we are returning a fresh round stat, with NumSubmissions: 0 tm.orm. - On("FindOrCreateFluxMonitorRoundStats", contractAddress, uint32(olderRoundID), uint(1)). + On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), uint(1)). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ PipelineRunID: corenull.NewInt64(int64(1), true), Aggregator: contractAddress, @@ -1795,16 +1795,16 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { tm.orm. On("UpdateFluxMonitorRoundStats", + mock.Anything, contractAddress, uint32(olderRoundID), int64(1), uint(1), - mock.Anything, ). Return(nil). Once() - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ RoundId: big.NewInt(olderRoundID), StartedAt: big.NewInt(0), @@ -1824,6 +1824,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), enableDrumbeatTicker("@every 3s", 2*time.Second)) tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil) + tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -1853,7 +1854,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { Return(roundState, nil). Once() - tm.orm.On("FindOrCreateFluxMonitorRoundStats", contractAddress, roundID, mock.Anything). + tm.orm.On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundID, mock.Anything). Return(fluxmonitorv2.FluxMonitorRoundStatsV2{Aggregator: contractAddress, RoundID: roundID}, nil). Once() @@ -1895,7 +1896,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { tm.pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = runID + args.Get(2).(*pipeline.Run).ID = runID }). Once() tm.contractSubmitter. @@ -1904,7 +1905,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { Once() tm.orm. - On("UpdateFluxMonitorRoundStats", contractAddress, roundID, runID, mock.Anything, mock.Anything). + On("UpdateFluxMonitorRoundStats", mock.Anything, contractAddress, roundID, runID, mock.Anything). Return(nil). Once() } diff --git a/core/services/fluxmonitorv2/key_store_test.go b/core/services/fluxmonitorv2/key_store_test.go index fdef2ade210..31e6c01e351 100644 --- a/core/services/fluxmonitorv2/key_store_test.go +++ b/core/services/fluxmonitorv2/key_store_test.go @@ -16,8 +16,7 @@ func TestKeyStore_EnabledKeysForChain(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(true) - ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() ks := fluxmonitorv2.NewKeyStore(ethKeyStore) @@ -43,8 +42,7 @@ func TestKeyStore_GetRoundRobinAddress(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(true) - ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go index 3154b4c86ee..ac67c353cfb 100644 --- a/core/services/fluxmonitorv2/mocks/contract_submitter.go +++ b/core/services/fluxmonitorv2/mocks/contract_submitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go index 6ff1616111b..0585611ed03 100644 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ b/core/services/fluxmonitorv2/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index 7b2aac75e2f..f831c854ce4 100644 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ b/core/services/fluxmonitorv2/mocks/key_store_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go index 287c7ebb5fa..7755543b405 100644 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ b/core/services/fluxmonitorv2/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -11,7 +11,7 @@ import ( mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) // ORM is an autogenerated mock type for the ORM type @@ -19,9 +19,9 @@ type ORM struct { mock.Mock } -// CountFluxMonitorRoundStats provides a mock function with given fields: -func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { - ret := _m.Called() +// CountFluxMonitorRoundStats provides a mock function with given fields: ctx +func (_m *ORM) CountFluxMonitorRoundStats(ctx context.Context) (int, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for CountFluxMonitorRoundStats") @@ -29,17 +29,17 @@ func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { var r0 int var r1 error - if rf, ok := ret.Get(0).(func() (int, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() int); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) int); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(int) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -65,17 +65,17 @@ func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Addr return r0 } -// DeleteFluxMonitorRoundsBackThrough provides a mock function with given fields: aggregator, roundID -func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error { - ret := _m.Called(aggregator, roundID) +// DeleteFluxMonitorRoundsBackThrough provides a mock function with given fields: ctx, aggregator, roundID +func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error { + ret := _m.Called(ctx, aggregator, roundID) if len(ret) == 0 { panic("no return value specified for DeleteFluxMonitorRoundsBackThrough") } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, uint32) error); ok { - r0 = rf(aggregator, roundID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32) error); ok { + r0 = rf(ctx, aggregator, roundID) } else { r0 = ret.Error(0) } @@ -83,9 +83,9 @@ func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, rou return r0 } -// FindOrCreateFluxMonitorRoundStats provides a mock function with given fields: aggregator, roundID, newRoundLogs -func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error) { - ret := _m.Called(aggregator, roundID, newRoundLogs) +// FindOrCreateFluxMonitorRoundStats provides a mock function with given fields: ctx, aggregator, roundID, newRoundLogs +func (_m *ORM) FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error) { + ret := _m.Called(ctx, aggregator, roundID, newRoundLogs) if len(ret) == 0 { panic("no return value specified for FindOrCreateFluxMonitorRoundStats") @@ -93,17 +93,17 @@ func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roun var r0 fluxmonitorv2.FluxMonitorRoundStatsV2 var r1 error - if rf, ok := ret.Get(0).(func(common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)); ok { - return rf(aggregator, roundID, newRoundLogs) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)); ok { + return rf(ctx, aggregator, roundID, newRoundLogs) } - if rf, ok := ret.Get(0).(func(common.Address, uint32, uint) fluxmonitorv2.FluxMonitorRoundStatsV2); ok { - r0 = rf(aggregator, roundID, newRoundLogs) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, uint) fluxmonitorv2.FluxMonitorRoundStatsV2); ok { + r0 = rf(ctx, aggregator, roundID, newRoundLogs) } else { r0 = ret.Get(0).(fluxmonitorv2.FluxMonitorRoundStatsV2) } - if rf, ok := ret.Get(1).(func(common.Address, uint32, uint) error); ok { - r1 = rf(aggregator, roundID, newRoundLogs) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, uint32, uint) error); ok { + r1 = rf(ctx, aggregator, roundID, newRoundLogs) } else { r1 = ret.Error(1) } @@ -111,9 +111,9 @@ func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roun return r0, r1 } -// MostRecentFluxMonitorRoundID provides a mock function with given fields: aggregator -func (_m *ORM) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, error) { - ret := _m.Called(aggregator) +// MostRecentFluxMonitorRoundID provides a mock function with given fields: ctx, aggregator +func (_m *ORM) MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) { + ret := _m.Called(ctx, aggregator) if len(ret) == 0 { panic("no return value specified for MostRecentFluxMonitorRoundID") @@ -121,17 +121,17 @@ func (_m *ORM) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, var r0 uint32 var r1 error - if rf, ok := ret.Get(0).(func(common.Address) (uint32, error)); ok { - return rf(aggregator) + if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint32, error)); ok { + return rf(ctx, aggregator) } - if rf, ok := ret.Get(0).(func(common.Address) uint32); ok { - r0 = rf(aggregator) + if rf, ok := ret.Get(0).(func(context.Context, common.Address) uint32); ok { + r0 = rf(ctx, aggregator) } else { r0 = ret.Get(0).(uint32) } - if rf, ok := ret.Get(1).(func(common.Address) error); ok { - r1 = rf(aggregator) + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, aggregator) } else { r1 = ret.Error(1) } @@ -139,24 +139,17 @@ func (_m *ORM) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, return r0, r1 } -// UpdateFluxMonitorRoundStats provides a mock function with given fields: aggregator, roundID, runID, newRoundLogsAddition, qopts -func (_m *ORM) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, aggregator, roundID, runID, newRoundLogsAddition) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateFluxMonitorRoundStats provides a mock function with given fields: ctx, aggregator, roundID, runID, newRoundLogsAddition +func (_m *ORM) UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error { + ret := _m.Called(ctx, aggregator, roundID, runID, newRoundLogsAddition) if len(ret) == 0 { panic("no return value specified for UpdateFluxMonitorRoundStats") } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, uint32, int64, uint, ...pg.QOpt) error); ok { - r0 = rf(aggregator, roundID, runID, newRoundLogsAddition, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, int64, uint) error); ok { + r0 = rf(ctx, aggregator, roundID, runID, newRoundLogsAddition) } else { r0 = ret.Error(0) } @@ -164,6 +157,26 @@ func (_m *ORM) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID ui return r0 } +// WithDataSource provides a mock function with given fields: _a0 +func (_m *ORM) WithDataSource(_a0 sqlutil.DataSource) fluxmonitorv2.ORM { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WithDataSource") + } + + var r0 fluxmonitorv2.ORM + if rf, ok := ret.Get(0).(func(sqlutil.DataSource) fluxmonitorv2.ORM); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(fluxmonitorv2.ORM) + } + } + + return r0 +} + // NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewORM(t interface { diff --git a/core/services/fluxmonitorv2/orm.go b/core/services/fluxmonitorv2/orm.go index 91973387e32..e090b84ed04 100644 --- a/core/services/fluxmonitorv2/orm.go +++ b/core/services/fluxmonitorv2/orm.go @@ -7,12 +7,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/jmoiron/sqlx" - + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type transmitter interface { @@ -23,48 +21,49 @@ type transmitter interface { // ORM defines an interface for database commands related to Flux Monitor v2 type ORM interface { - MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, error) - DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error - FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, error) - UpdateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint, qopts ...pg.QOpt) error + MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) + DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error + FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, error) + UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error CreateEthTransaction(ctx context.Context, fromAddress, toAddress common.Address, payload []byte, gasLimit uint64, idempotencyKey *string) error - CountFluxMonitorRoundStats() (count int, err error) + CountFluxMonitorRoundStats(ctx context.Context) (count int, err error) + + WithDataSource(sqlutil.DataSource) ORM } type orm struct { - q pg.Q + ds sqlutil.DataSource txm transmitter strategy types.TxStrategy checker txmgr.TransmitCheckerSpec logger logger.Logger } +func (o *orm) WithDataSource(ds sqlutil.DataSource) ORM { return o.withDataSource(ds) } + +func (o *orm) withDataSource(ds sqlutil.DataSource) *orm { + return &orm{ds, o.txm, o.strategy, o.checker, o.logger} +} + // NewORM initializes a new ORM -func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, txm transmitter, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec) ORM { +func NewORM(ds sqlutil.DataSource, lggr logger.Logger, txm transmitter, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec) ORM { namedLogger := lggr.Named("FluxMonitorORM") - q := pg.NewQ(db, namedLogger, cfg) - return &orm{ - q, - txm, - strategy, - checker, - namedLogger, - } + return &orm{ds, txm, strategy, checker, namedLogger} } // MostRecentFluxMonitorRoundID finds roundID of the most recent round that the // provided oracle address submitted to -func (o *orm) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, error) { +func (o *orm) MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) { var stats FluxMonitorRoundStatsV2 - err := o.q.Get(&stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator = $1 ORDER BY round_id DESC LIMIT 1`, aggregator) + err := o.ds.GetContext(ctx, &stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator = $1 ORDER BY round_id DESC LIMIT 1`, aggregator) return stats.RoundID, errors.Wrap(err, "MostRecentFluxMonitorRoundID failed") } // DeleteFluxMonitorRoundsBackThrough deletes all the RoundStat records for a // given oracle address starting from the most recent round back through the // given round -func (o *orm) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error { - _, err := o.q.Exec(` +func (o *orm) DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error { + _, err := o.ds.ExecContext(ctx, ` DELETE FROM flux_monitor_round_stats_v2 WHERE aggregator = $1 AND round_id >= $2 @@ -74,14 +73,14 @@ func (o *orm) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roun // FindOrCreateFluxMonitorRoundStats find the round stats record for a given // oracle on a given round, or creates it if no record exists -func (o *orm) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (stats FluxMonitorRoundStatsV2, err error) { - err = o.q.Transaction(func(tx pg.Queryer) error { - err = tx.Get(&stats, +func (o *orm) FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (stats FluxMonitorRoundStatsV2, err error) { + err = sqlutil.Transact(ctx, o.withDataSource, o.ds, nil, func(tx *orm) error { + err = tx.ds.GetContext(ctx, &stats, `INSERT INTO flux_monitor_round_stats_v2 (aggregator, round_id, num_new_round_logs, num_submissions) VALUES ($1, $2, $3, 0) ON CONFLICT (aggregator, round_id) DO NOTHING`, aggregator, roundID, newRoundLogs) if errors.Is(err, sql.ErrNoRows) { - err = tx.Get(&stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator=$1 AND round_id=$2`, aggregator, roundID) + err = tx.ds.GetContext(ctx, &stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator=$1 AND round_id=$2`, aggregator, roundID) } return err }) @@ -91,9 +90,8 @@ func (o *orm) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, round // UpdateFluxMonitorRoundStats trys to create a RoundStat record for the given oracle // at the given round. If one already exists, it increments the num_submissions column. -func (o *orm) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error { + _, err := o.ds.ExecContext(ctx, ` INSERT INTO flux_monitor_round_stats_v2 ( aggregator, round_id, pipeline_run_id, num_new_round_logs, num_submissions ) VALUES ( @@ -108,8 +106,8 @@ func (o *orm) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID uin } // CountFluxMonitorRoundStats counts the total number of records -func (o *orm) CountFluxMonitorRoundStats() (count int, err error) { - err = o.q.Get(&count, `SELECT count(*) FROM flux_monitor_round_stats_v2`) +func (o *orm) CountFluxMonitorRoundStats(ctx context.Context) (count int, err error) { + err = o.ds.GetContext(ctx, &count, `SELECT count(*) FROM flux_monitor_round_stats_v2`) return count, errors.Wrap(err, "CountFluxMonitorRoundStats failed") } diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 9b31525831b..db00fabb4ff 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -28,77 +29,78 @@ import ( func TestORM_MostRecentFluxMonitorRoundID(t *testing.T) { t.Parallel() + ctx := tests.Context(t) db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(true) - orm := newORM(t, db, cfg, nil) + orm := newORM(t, db, nil) address := testutils.NewAddress() // Setup the rounds for round := uint32(0); round < 10; round++ { - _, err := orm.FindOrCreateFluxMonitorRoundStats(address, round, 1) + _, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, round, 1) require.NoError(t, err) } - count, err := orm.CountFluxMonitorRoundStats() + count, err := orm.CountFluxMonitorRoundStats(ctx) require.NoError(t, err) require.Equal(t, 10, count) // Ensure round stats are not created again for the same address/roundID - stats, err := orm.FindOrCreateFluxMonitorRoundStats(address, uint32(0), 1) + stats, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, uint32(0), 1) require.NoError(t, err) require.Equal(t, uint32(0), stats.RoundID) require.Equal(t, address, stats.Aggregator) require.Equal(t, uint64(1), stats.NumNewRoundLogs) - count, err = orm.CountFluxMonitorRoundStats() + count, err = orm.CountFluxMonitorRoundStats(ctx) require.NoError(t, err) require.Equal(t, 10, count) - roundID, err := orm.MostRecentFluxMonitorRoundID(testutils.NewAddress()) + roundID, err := orm.MostRecentFluxMonitorRoundID(ctx, testutils.NewAddress()) require.Error(t, err) require.Equal(t, uint32(0), roundID) - roundID, err = orm.MostRecentFluxMonitorRoundID(address) + roundID, err = orm.MostRecentFluxMonitorRoundID(ctx, address) require.NoError(t, err) require.Equal(t, uint32(9), roundID) // Deleting rounds against a new address should incur no changes - err = orm.DeleteFluxMonitorRoundsBackThrough(testutils.NewAddress(), 5) + err = orm.DeleteFluxMonitorRoundsBackThrough(ctx, testutils.NewAddress(), 5) require.NoError(t, err) - count, err = orm.CountFluxMonitorRoundStats() + count, err = orm.CountFluxMonitorRoundStats(ctx) require.NoError(t, err) require.Equal(t, 10, count) // Deleting rounds against the address - err = orm.DeleteFluxMonitorRoundsBackThrough(address, 5) + err = orm.DeleteFluxMonitorRoundsBackThrough(ctx, address, 5) require.NoError(t, err) - count, err = orm.CountFluxMonitorRoundStats() + count, err = orm.CountFluxMonitorRoundStats(ctx) require.NoError(t, err) require.Equal(t, 5, count) } func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { t.Parallel() + ctx := tests.Context(t) cfg := configtest.NewGeneralConfig(t, nil) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) lggr := logger.TestLogger(t) // Instantiate a real pipeline ORM because we need to create a pipeline run // for the foreign key constraint of the stats record - pipelineORM := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db) // Instantiate a real job ORM because we need to create a job to satisfy // a check in pipeline.CreateRun jobORM := job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr, cfg.Database()) - orm := newORM(t, db, cfg.Database(), nil) + orm := newORM(t, db, nil) address := testutils.NewAddress() var roundID uint32 = 1 @@ -129,13 +131,13 @@ func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { }, }, } - err := pipelineORM.InsertFinishedRun(run, true) + err := pipelineORM.InsertFinishedRun(ctx, run, true) require.NoError(t, err) - err = orm.UpdateFluxMonitorRoundStats(address, roundID, run.ID, 0) + err = orm.UpdateFluxMonitorRoundStats(ctx, address, roundID, run.ID, 0) require.NoError(t, err) - stats, err := orm.FindOrCreateFluxMonitorRoundStats(address, roundID, 0) + stats, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, roundID, 0) require.NoError(t, err) require.Equal(t, expectedCount, stats.NumSubmissions) require.True(t, stats.PipelineRunID.Valid) @@ -170,14 +172,13 @@ func TestORM_CreateEthTransaction(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(true) - ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() strategy := commontxmmocks.NewTxStrategy(t) var ( txm = txmmocks.NewMockEvmTxManager(t) - orm = fluxmonitorv2.NewORM(db, logger.TestLogger(t), cfg, txm, strategy, txmgr.TransmitCheckerSpec{}) + orm = fluxmonitorv2.NewORM(db, logger.TestLogger(t), txm, strategy, txmgr.TransmitCheckerSpec{}) _, from = cltest.MustInsertRandomKey(t, ethKeyStore) to = testutils.NewAddress() diff --git a/core/services/fluxmonitorv2/payment_checker_test.go b/core/services/fluxmonitorv2/payment_checker_test.go index baec5642339..88643a69fb2 100644 --- a/core/services/fluxmonitorv2/payment_checker_test.go +++ b/core/services/fluxmonitorv2/payment_checker_test.go @@ -11,6 +11,7 @@ import ( ) func TestPaymentChecker_SufficientFunds(t *testing.T) { + t.Parallel() var ( checker = fluxmonitorv2.NewPaymentChecker(nil, nil) payment = 100 @@ -44,6 +45,7 @@ func TestPaymentChecker_SufficientFunds(t *testing.T) { } func TestPaymentChecker_SufficientPayment(t *testing.T) { + t.Parallel() var ( payment int64 = 10 eq = payment diff --git a/core/services/fluxmonitorv2/poll_manager_test.go b/core/services/fluxmonitorv2/poll_manager_test.go index 9245c309c27..be6aa9a819b 100644 --- a/core/services/fluxmonitorv2/poll_manager_test.go +++ b/core/services/fluxmonitorv2/poll_manager_test.go @@ -84,6 +84,7 @@ func watchTicks(t *testing.T, pm *fluxmonitorv2.PollManager, waitDuration time.D } func TestPollManager_PollTicker(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: pollTickerDefaultDuration, PollTickerDisabled: false, @@ -104,6 +105,7 @@ func TestPollManager_PollTicker(t *testing.T) { } func TestPollManager_IdleTimer(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: 100 * time.Millisecond, PollTickerDisabled: true, @@ -126,6 +128,7 @@ func TestPollManager_IdleTimer(t *testing.T) { } func TestPollManager_RoundTimer(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: pollTickerDefaultDuration, PollTickerDisabled: true, @@ -149,6 +152,7 @@ func TestPollManager_RoundTimer(t *testing.T) { } func TestPollManager_RetryTimer(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: pollTickerDefaultDuration, PollTickerDisabled: true, @@ -185,6 +189,7 @@ func TestPollManager_RetryTimer(t *testing.T) { } func TestPollManager_InitialPoll(t *testing.T) { + t.Parallel() pm := newPollManager(t) pm.Start(false, flux_aggregator_wrapper.OracleRoundState{}) @@ -193,6 +198,7 @@ func TestPollManager_InitialPoll(t *testing.T) { } func TestPollManager_HibernationTimer(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: pollTickerDefaultDuration, PollTickerDisabled: true, @@ -214,6 +220,7 @@ func TestPollManager_HibernationTimer(t *testing.T) { } func TestPollManager_HibernationOnStartThenAwaken(t *testing.T) { + t.Parallel() pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ PollTickerInterval: pollTickerDefaultDuration, PollTickerDisabled: false, @@ -248,6 +255,7 @@ func TestPollManager_HibernationOnStartThenAwaken(t *testing.T) { } func TestPollManager_AwakeOnStartThenHibernate(t *testing.T) { + t.Parallel() pm := newPollManager(t) pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ @@ -272,6 +280,7 @@ func TestPollManager_AwakeOnStartThenHibernate(t *testing.T) { } func TestPollManager_ShouldPerformInitialPoll(t *testing.T) { + t.Parallel() testCases := []struct { name string pollTickerDisabled bool @@ -339,6 +348,7 @@ func TestPollManager_ShouldPerformInitialPoll(t *testing.T) { } func TestPollManager_Stop(t *testing.T) { + t.Parallel() pm := newPollManager(t) pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ @@ -362,6 +372,7 @@ func TestPollManager_Stop(t *testing.T) { } func TestPollManager_ResetIdleTimer(t *testing.T) { + t.Parallel() pm := newPollManager(t) // Start again in awake mode @@ -382,6 +393,7 @@ func TestPollManager_ResetIdleTimer(t *testing.T) { } func TestPollManager_ResetIdleTimerWhenHibernating(t *testing.T) { + t.Parallel() pm := newPollManager(t) // Start in hibernation @@ -402,6 +414,7 @@ func TestPollManager_ResetIdleTimerWhenHibernating(t *testing.T) { } func TestPollManager_Reset(t *testing.T) { + t.Parallel() pm := newPollManager(t) // Start again in awake mode @@ -429,6 +442,7 @@ func TestPollManager_Reset(t *testing.T) { } func TestPollManager_ResetWhenHibernating(t *testing.T) { + t.Parallel() pm := newPollManager(t) // Start in hibernation diff --git a/core/services/fluxmonitorv2/submission_checker_test.go b/core/services/fluxmonitorv2/submission_checker_test.go index f8c63fef4bd..ae543c772a5 100644 --- a/core/services/fluxmonitorv2/submission_checker_test.go +++ b/core/services/fluxmonitorv2/submission_checker_test.go @@ -11,6 +11,7 @@ import ( ) func TestSubmissionChecker_IsValid(t *testing.T) { + t.Parallel() testCases := []struct { name string answer decimal.Decimal diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go index 40efd1d724d..81d9215bea8 100644 --- a/core/services/fluxmonitorv2/validate_test.go +++ b/core/services/fluxmonitorv2/validate_test.go @@ -21,6 +21,7 @@ func (testcfg) DefaultHTTPTimeout() commonconfig.Duration { } func TestValidate(t *testing.T) { + t.Parallel() var tt = []struct { name string toml string diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index d6cd9aa23d6..f3754bbbc29 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -85,7 +85,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()) + kst := cltest.NewKeyStore(t, db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, KeyStore: kst.Eth(), LogBroadcaster: broadcaster, MailMon: mailMon}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) diff --git a/core/services/functions/mocks/bridge_accessor.go b/core/services/functions/mocks/bridge_accessor.go index 4978da55d8b..797007d7886 100644 --- a/core/services/functions/mocks/bridge_accessor.go +++ b/core/services/functions/mocks/bridge_accessor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/external_adapter_client.go b/core/services/functions/mocks/external_adapter_client.go index dbf4081c95d..cd402c1e6a5 100644 --- a/core/services/functions/mocks/external_adapter_client.go +++ b/core/services/functions/mocks/external_adapter_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/functions_listener.go b/core/services/functions/mocks/functions_listener.go index d63248f00cf..fed369fd659 100644 --- a/core/services/functions/mocks/functions_listener.go +++ b/core/services/functions/mocks/functions_listener.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/offchain_transmitter.go b/core/services/functions/mocks/offchain_transmitter.go index 5eee967e685..1e1422b8d46 100644 --- a/core/services/functions/mocks/offchain_transmitter.go +++ b/core/services/functions/mocks/offchain_transmitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/orm.go b/core/services/functions/mocks/orm.go index ff72916171b..c921fda5c69 100644 --- a/core/services/functions/mocks/orm.go +++ b/core/services/functions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/gateway_connector.go b/core/services/gateway/connector/mocks/gateway_connector.go index ba972425f66..0f37ee6040a 100644 --- a/core/services/gateway/connector/mocks/gateway_connector.go +++ b/core/services/gateway/connector/mocks/gateway_connector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/gateway_connector_handler.go b/core/services/gateway/connector/mocks/gateway_connector_handler.go index e83e06b60e3..c21528134f7 100644 --- a/core/services/gateway/connector/mocks/gateway_connector_handler.go +++ b/core/services/gateway/connector/mocks/gateway_connector_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/signer.go b/core/services/gateway/connector/mocks/signer.go index 18c7186f7fc..bb4c3648397 100644 --- a/core/services/gateway/connector/mocks/signer.go +++ b/core/services/gateway/connector/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/delegate.go b/core/services/gateway/delegate.go index ba34f2894de..8cddc027803 100644 --- a/core/services/gateway/delegate.go +++ b/core/services/gateway/delegate.go @@ -41,10 +41,10 @@ func (d *Delegate) JobType() job.Type { return job.Gateway } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec returns the scheduler to be used for running observer jobs func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go index 6668a3c76ff..7581414d00f 100644 --- a/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go index 76121270518..c1d47169c51 100644 --- a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go +++ b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go index 5f2054c4e47..93b476820a4 100644 --- a/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go index 16a82a488b4..614ba83af17 100644 --- a/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/subscriptions/orm_test.go b/core/services/gateway/handlers/functions/subscriptions/orm_test.go index f75ab0b98c1..e2d7cfe9f49 100644 --- a/core/services/gateway/handlers/functions/subscriptions/orm_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/orm_test.go @@ -237,6 +237,7 @@ func TestORM_UpsertSubscription(t *testing.T) { }) } func Test_NewORM(t *testing.T) { + t.Parallel() t.Run("OK-create_ORM", func(t *testing.T) { _, err := subscriptions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), testutils.NewAddress()) require.NoError(t, err) diff --git a/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go index 212029b73f7..04a5d14102f 100644 --- a/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go @@ -29,6 +29,7 @@ const ( ) func TestSubscriptions_OnePass(t *testing.T) { + t.Parallel() getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000003") getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") @@ -72,6 +73,7 @@ func TestSubscriptions_OnePass(t *testing.T) { } func TestSubscriptions_MultiPass(t *testing.T) { + t.Parallel() const ncycles int32 = 5 var currentCycle atomic.Int32 getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000006") @@ -119,6 +121,7 @@ func TestSubscriptions_MultiPass(t *testing.T) { } func TestSubscriptions_Stored(t *testing.T) { + t.Parallel() getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000003") getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") diff --git a/core/services/gateway/handlers/mocks/don.go b/core/services/gateway/handlers/mocks/don.go index 6e88708dd7d..91c162b2f55 100644 --- a/core/services/gateway/handlers/mocks/don.go +++ b/core/services/gateway/handlers/mocks/don.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/mocks/handler.go b/core/services/gateway/handlers/mocks/handler.go index 7dfe1eae784..e22c7f158f3 100644 --- a/core/services/gateway/handlers/mocks/handler.go +++ b/core/services/gateway/handlers/mocks/handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/connection_acceptor.go b/core/services/gateway/network/mocks/connection_acceptor.go index c45cc7fbe3e..37ebc7b8c9e 100644 --- a/core/services/gateway/network/mocks/connection_acceptor.go +++ b/core/services/gateway/network/mocks/connection_acceptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/connection_initiator.go b/core/services/gateway/network/mocks/connection_initiator.go index 87e4f407328..7efac288ba8 100644 --- a/core/services/gateway/network/mocks/connection_initiator.go +++ b/core/services/gateway/network/mocks/connection_initiator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/http_request_handler.go b/core/services/gateway/network/mocks/http_request_handler.go index 7c5ff4025cf..0cbcf3eb6b1 100644 --- a/core/services/gateway/network/mocks/http_request_handler.go +++ b/core/services/gateway/network/mocks/http_request_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/http_server.go b/core/services/gateway/network/mocks/http_server.go index 81e180e7b8d..586677c604c 100644 --- a/core/services/gateway/network/mocks/http_server.go +++ b/core/services/gateway/network/mocks/http_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/web_socket_server.go b/core/services/gateway/network/mocks/web_socket_server.go index 4f75f3b7d0f..fb880193c7e 100644 --- a/core/services/gateway/network/mocks/web_socket_server.go +++ b/core/services/gateway/network/mocks/web_socket_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index a7543753d63..22e1b0bef63 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -214,10 +213,10 @@ func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralC ExternalJobID: uuid.New(), } s := fmt.Sprintf(minimalNonBootstrapTemplate, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout) - keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) + keyStore := cltest.NewKeyStore(t, db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: evmtest.NewEthClientMockWithDefaultChain(t), GeneralConfig: cfg, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - _, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + _, err := ocr.ValidatedOracleSpecToml(cfg, legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &os) require.NoError(t, err) @@ -272,6 +271,7 @@ func makeOCRJobSpecFromToml(t *testing.T, jobSpecToml string) *job.Job { func makeOCR2VRFJobSpec(t testing.TB, ks keystore.Master, cfg chainlink.GeneralConfig, transmitter common.Address, chainID *big.Int, fromBlock uint64) *job.Job { t.Helper() + ctx := testutils.Context(t) useForwarders := false _, beacon := cltest.MustInsertRandomKey(t, ks.Eth()) @@ -279,7 +279,7 @@ func makeOCR2VRFJobSpec(t testing.TB, ks keystore.Master, cfg chainlink.GeneralC _, feed := cltest.MustInsertRandomKey(t, ks.Eth()) _, dkg := cltest.MustInsertRandomKey(t, ks.Eth()) sendingKeys := fmt.Sprintf(`"%s"`, transmitter) - kb, _ := ks.OCR2().Create(chaintype.EVM) + kb, _ := ks.OCR2().Create(ctx, chaintype.EVM) vrfKey := make([]byte, 32) _, err := rand.Read(vrfKey) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index a6e3622df1b..ffbd02c512b 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -40,7 +40,6 @@ import ( ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -74,15 +73,16 @@ serverPubKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707 func TestORM(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -338,15 +338,16 @@ func TestORM(t *testing.T) { func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewGeneralConfig(t, nil) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) korm := keeper.NewORM(db, logger.TestLogger(t)) @@ -358,7 +359,7 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ TransmitterAddress: address.Hex(), DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), @@ -395,7 +396,7 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { }) t.Run("it creates and deletes records for vrf jobs", func(t *testing.T) { - key, err := keyStore.VRF().Create() + key, err := keyStore.VRF().Create(testutils.Context(t)) require.NoError(t, err) pk := key.PublicKey jb, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: pk.String()}).Toml()) @@ -438,13 +439,14 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { } func TestORM_CreateJob_VRFV2(t *testing.T) { + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -522,13 +524,14 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { } func TestORM_CreateJob_VRFV2Plus(t *testing.T) { + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -609,13 +612,14 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { } func TestORM_CreateJob_OCRBootstrap(t *testing.T) { + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -638,10 +642,10 @@ func TestORM_CreateJob_OCRBootstrap(t *testing.T) { func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { config := configtest.NewGeneralConfig(t, nil) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -720,6 +724,7 @@ func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { } func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { + ctx := testutils.Context(t) customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -732,11 +737,11 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { }) }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -759,7 +764,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { }) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, spec.Toml()) + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, spec.Toml()) require.NoError(t, err) t.Run("with a set chain id", func(t *testing.T) { @@ -771,7 +776,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} spec.JobID = externalJobID.UUID.String() - jba, err := ocr.ValidatedOracleSpecToml(legacyChains, spec.Toml()) + jba, err := ocr.ValidatedOracleSpecToml(config, legacyChains, spec.Toml()) require.NoError(t, err) err = jobORM.CreateJob(&jba) // Try to add duplicate job with default id require.Error(t, err) @@ -779,7 +784,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} spec.JobID = externalJobID.UUID.String() - jb2, err := ocr.ValidatedOracleSpecToml(legacyChains, spec.Toml()) + jb2, err := ocr.ValidatedOracleSpecToml(config, legacyChains, spec.Toml()) require.NoError(t, err) err = jobORM.CreateJob(&jb2) // Try to add duplicate job with custom id @@ -789,6 +794,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { + ctx := testutils.Context(t) customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -801,11 +807,11 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { }) }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -850,6 +856,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing.T) { + ctx := testutils.Context(t) customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -862,11 +869,11 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing }) }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -904,10 +911,11 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing } func TestORM_ValidateKeyStoreMatch(t *testing.T) { + ctx := testutils.Context(t) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {}) - keyStore := cltest.NewKeyStore(t, pgtest.NewSqlxDB(t), config.Database()) - require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) + keyStore := cltest.NewKeyStore(t, pgtest.NewSqlxDB(t)) + require.NoError(t, keyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) var jb job.Job { @@ -918,7 +926,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test ETH key validation", func(t *testing.T) { ctx := testutils.Context(t) - jb.OCR2OracleSpec.Relay = relay.EVM + jb.OCR2OracleSpec.Relay = types.NetworkEVM err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no EVM key matching: \"bad key\"") @@ -929,11 +937,11 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Cosmos key validation", func(t *testing.T) { ctx := testutils.Context(t) - jb.OCR2OracleSpec.Relay = relay.Cosmos + jb.OCR2OracleSpec.Relay = types.NetworkCosmos err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Cosmos key matching: \"bad key\"") - cosmosKey, err := keyStore.Cosmos().Create() + cosmosKey, err := keyStore.Cosmos().Create(ctx) require.NoError(t, err) err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, cosmosKey.ID()) require.NoError(t, err) @@ -941,12 +949,12 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Solana key validation", func(t *testing.T) { ctx := testutils.Context(t) - jb.OCR2OracleSpec.Relay = relay.Solana + jb.OCR2OracleSpec.Relay = types.NetworkSolana err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Solana key matching: \"bad key\"") - solanaKey, err := keyStore.Solana().Create() + solanaKey, err := keyStore.Solana().Create(ctx) require.NoError(t, err) err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, solanaKey.ID()) require.NoError(t, err) @@ -954,11 +962,11 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Starknet key validation", func(t *testing.T) { ctx := testutils.Context(t) - jb.OCR2OracleSpec.Relay = relay.StarkNet + jb.OCR2OracleSpec.Relay = types.NetworkStarkNet err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Starknet key matching: \"bad key\"") - starkNetKey, err := keyStore.StarkNet().Create() + starkNetKey, err := keyStore.StarkNet().Create(ctx) require.NoError(t, err) err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, starkNetKey.ID()) require.NoError(t, err) @@ -970,7 +978,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no CSA key matching: \"bad key\"") - csaKey, err := keyStore.CSA().Create() + csaKey, err := keyStore.CSA().Create(ctx) require.NoError(t, err) err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, csaKey.ID()) require.NoError(t, err) @@ -979,14 +987,15 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { func Test_FindJobs(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -997,7 +1006,7 @@ func Test_FindJobs(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - jb1, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb1, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: uuid.New().String(), TransmitterAddress: address.Hex(), @@ -1047,6 +1056,7 @@ func Test_FindJobs(t *testing.T) { func Test_FindJob(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) // Create a config with multiple EVM chains. The test fixtures already load 1337 // Additional chains will need additional fixture statements to add a chain to evm_chains. @@ -1062,12 +1072,12 @@ func Test_FindJob(t *testing.T) { }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) - require.NoError(t, keyStore.CSA().Add(cltest.DefaultCSAKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) + require.NoError(t, keyStore.CSA().Add(ctx, cltest.DefaultCSAKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -1081,7 +1091,7 @@ func Test_FindJob(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - job, err := ocr.ValidatedOracleSpecToml(legacyChains, + job, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), Name: "orig ocr spec", @@ -1092,7 +1102,7 @@ func Test_FindJob(t *testing.T) { ) require.NoError(t, err) - jobSameAddress, err := ocr.ValidatedOracleSpecToml(legacyChains, + jobSameAddress, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: uuid.New().String(), TransmitterAddress: address.Hex(), @@ -1244,13 +1254,14 @@ func Test_FindJob(t *testing.T) { func Test_FindJobsByPipelineSpecIDs(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -1291,14 +1302,15 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { func Test_FindPipelineRuns(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -1309,7 +1321,7 @@ func Test_FindPipelineRuns(t *testing.T) { externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), @@ -1351,15 +1363,16 @@ func Test_FindPipelineRuns(t *testing.T) { func Test_PipelineRunsByJobID(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -1370,7 +1383,7 @@ func Test_PipelineRunsByJobID(t *testing.T) { externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), @@ -1410,16 +1423,17 @@ func Test_PipelineRunsByJobID(t *testing.T) { } func Test_FindPipelineRunIDsByJobID(t *testing.T) { + ctx := testutils.Context(t) var jb job.Job config := configtest.NewTestGeneralConfig(t) _, db := heavyweight.FullTestDBV2(t, nil) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -1435,7 +1449,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { key, err := ethkey.NewV2() require.NoError(t, err) - jb, err = ocr.ValidatedOracleSpecToml(legacyChains, + jb, err = ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: jobID, Name: fmt.Sprintf("Job #%v", jobID), @@ -1519,15 +1533,16 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { func Test_FindPipelineRunsByIDs(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -1538,7 +1553,7 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), @@ -1577,15 +1592,16 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { func Test_FindPipelineRunByID(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - err := keyStore.OCR().Add(cltest.DefaultOCRKey) + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) require.NoError(t, err) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -1620,15 +1636,16 @@ func Test_FindPipelineRunByID(t *testing.T) { func Test_FindJobWithoutSpecErrors(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - err := keyStore.OCR().Add(cltest.DefaultOCRKey) + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) require.NoError(t, err) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -1657,15 +1674,16 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { func Test_FindSpecErrorsByJobIDs(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - err := keyStore.OCR().Add(cltest.DefaultOCRKey) + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) require.NoError(t, err) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -1691,15 +1709,16 @@ func Test_FindSpecErrorsByJobIDs(t *testing.T) { func Test_CountPipelineRunsByJobID(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -1710,7 +1729,7 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ JobID: externalJobID.String(), TransmitterAddress: address.Hex(), @@ -1740,6 +1759,7 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { func mustInsertPipelineRun(t *testing.T, orm pipeline.ORM, j job.Job) pipeline.Run { t.Helper() + ctx := testutils.Context(t) run := pipeline.Run{ PipelineSpecID: j.PipelineSpecID, @@ -1750,7 +1770,7 @@ func mustInsertPipelineRun(t *testing.T, orm pipeline.ORM, j job.Job) pipeline.R CreatedAt: time.Now(), FinishedAt: null.Time{}, } - err := orm.CreateRun(&run) + err := orm.CreateRun(ctx, &run) require.NoError(t, err) return run } diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index 698e60eca7b..33ee6dc306c 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -29,6 +29,7 @@ func clearJobsDb(t *testing.T, db *sqlx.DB) { } func TestPipelineORM_Integration(t *testing.T) { + ctx := testutils.Context(t) const DotStr = ` // data source 1 ds1 [type=bridge name=voter_turnout]; @@ -51,11 +52,11 @@ func TestPipelineORM_Integration(t *testing.T) { c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(30 * time.Millisecond) }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) var specID int32 @@ -126,14 +127,15 @@ func TestPipelineORM_Integration(t *testing.T) { _, bridge2 := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}) t.Run("creates task DAGs", func(t *testing.T) { + ctx := testutils.Context(t) clearJobsDb(t, db) - orm := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + orm := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) p, err := pipeline.Parse(DotStr) require.NoError(t, err) - specID, err = orm.CreateSpec(*p, models.Interval(0)) + specID, err = orm.CreateSpec(ctx, nil, *p, models.Interval(0)) require.NoError(t, err) var pipelineSpecs []pipeline.Spec @@ -152,7 +154,7 @@ func TestPipelineORM_Integration(t *testing.T) { lggr := logger.TestLogger(t) cfg := configtest.NewTestGeneralConfig(t) clearJobsDb(t, db) - orm := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + orm := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{Client: evmtest.NewEthClientMockWithDefaultChain(t), DB: db, GeneralConfig: config, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) diff --git a/core/services/job/kv_orm_test.go b/core/services/job/kv_orm_test.go index 6a3269e9992..156779ffb4d 100644 --- a/core/services/job/kv_orm_test.go +++ b/core/services/job/kv_orm_test.go @@ -29,12 +29,12 @@ func TestJobKVStore(t *testing.T) { lggr := logger.TestLogger(t) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobID := int32(1337) kvStore := job.NewKVStore(jobID, db, config.Database(), lggr) - jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, cltest.NewKeyStore(t, db, config.Database()), config.Database()) + jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, cltest.NewKeyStore(t, db), config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) diff --git a/core/services/job/mocks/kv_store.go b/core/services/job/mocks/kv_store.go index 139978f3579..270a6c1d554 100644 --- a/core/services/job/mocks/kv_store.go +++ b/core/services/job/mocks/kv_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 44b8c1f5be8..b8534b9d688 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/service_ctx.go b/core/services/job/mocks/service_ctx.go index 43c28632963..d01ef619be3 100644 --- a/core/services/job/mocks/service_ctx.go +++ b/core/services/job/mocks/service_ctx.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/spawner.go b/core/services/job/mocks/spawner.go index 60d36b18fa5..37e883ef3c5 100644 --- a/core/services/job/mocks/spawner.go +++ b/core/services/job/mocks/spawner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/job/models.go b/core/services/job/models.go index 67b7b8b0bbe..0c6390b3dbf 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -25,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" @@ -327,15 +326,32 @@ func (r JSONConfig) MercuryCredentialName() (string, error) { return name, nil } +func (r JSONConfig) ApplyDefaultsOCR2(cfg ocr2Config) { + _, ok := r["defaultTransactionQueueDepth"] + if !ok { + r["defaultTransactionQueueDepth"] = cfg.DefaultTransactionQueueDepth() + } + _, ok = r["simulateTransactions"] + if !ok { + r["simulateTransactions"] = cfg.SimulateTransactions() + } +} + +type ocr2Config interface { + DefaultTransactionQueueDepth() uint32 + SimulateTransactions() bool +} + var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions} // OCR2OracleSpec defines the job spec for OCR2 jobs. // Relay config is chain specific config for a relay (chain adapter). type OCR2OracleSpec struct { - ID int32 `toml:"-"` - ContractID string `toml:"contractID"` - FeedID *common.Hash `toml:"feedID"` - Relay relay.Network `toml:"relay"` + ID int32 `toml:"-"` + ContractID string `toml:"contractID"` + FeedID *common.Hash `toml:"feedID"` + // Network + Relay string `toml:"relay"` // TODO BCF-2442 implement ChainID as top level parameter rathe than buried in RelayConfig. ChainID string `toml:"chainID"` RelayConfig JSONConfig `toml:"relayConfig"` @@ -354,9 +370,9 @@ type OCR2OracleSpec struct { CaptureAutomationCustomTelemetry bool `toml:"captureAutomationCustomTelemetry"` } -func validateRelayID(id relay.ID) error { +func validateRelayID(id types.RelayID) error { // only the EVM has specific requirements - if id.Network == relay.EVM { + if id.Network == types.NetworkEVM { _, err := toml.ChainIDInt64(id.ChainID) if err != nil { return fmt.Errorf("invalid EVM chain id %s: %w", id.ChainID, err) @@ -365,20 +381,20 @@ func validateRelayID(id relay.ID) error { return nil } -func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { +func (s *OCR2OracleSpec) RelayID() (types.RelayID, error) { cid, err := s.getChainID() if err != nil { - return relay.ID{}, err + return types.RelayID{}, err } - rid := relay.NewID(s.Relay, cid) + rid := types.NewRelayID(s.Relay, cid) err = validateRelayID(rid) if err != nil { - return relay.ID{}, err + return types.RelayID{}, err } return rid, nil } -func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { +func (s *OCR2OracleSpec) getChainID() (string, error) { if s.ChainID != "" { return s.ChainID, nil } @@ -386,7 +402,7 @@ func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { return s.getChainIdFromRelayConfig() } -func (s *OCR2OracleSpec) getChainIdFromRelayConfig() (relay.ChainID, error) { +func (s *OCR2OracleSpec) getChainIdFromRelayConfig() (string, error) { v, exists := s.RelayConfig["chainID"] if !exists { @@ -738,10 +754,10 @@ type LegacyGasStationSidecarSpec struct { // BootstrapSpec defines the spec to handles the node communication setup process. type BootstrapSpec struct { - ID int32 `toml:"-"` - ContractID string `toml:"contractID"` - FeedID *common.Hash `toml:"feedID"` - Relay relay.Network `toml:"relay"` + ID int32 `toml:"-"` + ContractID string `toml:"contractID"` + FeedID *common.Hash `toml:"feedID"` + Relay string `toml:"relay"` // RelayID.Network RelayConfig JSONConfig MonitoringEndpoint null.String `toml:"monitoringEndpoint"` BlockchainTimeout models.Interval `toml:"blockchainTimeout"` diff --git a/core/services/job/models_test.go b/core/services/job/models_test.go index fa15e3b1b22..4d10fbb43c4 100644 --- a/core/services/job/models_test.go +++ b/core/services/job/models_test.go @@ -12,51 +12,50 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { type fields struct { - Relay relay.Network + Relay string ChainID string RelayConfig JSONConfig } tests := []struct { name string fields fields - want relay.ID + want types.RelayID wantErr bool }{ {name: "err no chain id", fields: fields{}, - want: relay.ID{}, + want: types.RelayID{}, wantErr: true, }, { name: "evm explicitly configured", fields: fields{ - Relay: relay.EVM, + Relay: types.NetworkEVM, ChainID: "1", }, - want: relay.ID{Network: relay.EVM, ChainID: "1"}, + want: types.RelayID{Network: types.NetworkEVM, ChainID: "1"}, }, { name: "evm implicitly configured", fields: fields{ - Relay: relay.EVM, + Relay: types.NetworkEVM, RelayConfig: map[string]any{"chainID": 1}, }, - want: relay.ID{Network: relay.EVM, ChainID: "1"}, + want: types.RelayID{Network: types.NetworkEVM, ChainID: "1"}, }, { name: "evm implicitly configured with bad value", fields: fields{ - Relay: relay.EVM, + Relay: types.NetworkEVM, RelayConfig: map[string]any{"chainID": float32(1)}, }, - want: relay.ID{}, + want: types.RelayID{}, wantErr: true, }, } @@ -91,7 +90,7 @@ var ( func TestOCR2OracleSpec(t *testing.T) { val := OCR2OracleSpec{ - Relay: relay.EVM, + Relay: types.NetworkEVM, PluginType: types.Median, ContractID: "foo", OCRKeyBundleID: null.StringFrom("bar"), diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 4ac1e7c6047..f7238799634 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -31,7 +31,6 @@ import ( medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -456,7 +455,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { o.lggr.Panicf("Unsupported jb.Type: %v", jb.Type) } - pipelineSpecID, err := o.pipelineORM.CreateSpec(p, jb.MaxTaskDuration, pg.WithQueryer(tx)) + pipelineSpecID, err := o.pipelineORM.CreateSpec(ctx, tx, p, jb.MaxTaskDuration) if err != nil { return errors.Wrap(err, "failed to create pipeline spec") } @@ -488,24 +487,24 @@ func ValidateKeyStoreMatch(ctx context.Context, spec *OCR2OracleSpec, keyStore k return } -func validateKeyStoreMatchForRelay(ctx context.Context, network relay.Network, keyStore keystore.Master, key string) error { +func validateKeyStoreMatchForRelay(ctx context.Context, network string, keyStore keystore.Master, key string) error { switch network { - case relay.EVM: + case types.NetworkEVM: _, err := keyStore.Eth().Get(ctx, key) if err != nil { return errors.Errorf("no EVM key matching: %q", key) } - case relay.Cosmos: + case types.NetworkCosmos: _, err := keyStore.Cosmos().Get(key) if err != nil { return errors.Errorf("no Cosmos key matching: %q", key) } - case relay.Solana: + case types.NetworkSolana: _, err := keyStore.Solana().Get(key) if err != nil { return errors.Errorf("no Solana key matching: %q", key) } - case relay.StarkNet: + case types.NetworkStarkNet: _, err := keyStore.StarkNet().Get(key) if err != nil { return errors.Errorf("no Starknet key matching: %q", key) diff --git a/core/services/job/orm_test.go b/core/services/job/orm_test.go index 2e19669417a..fb0e846b9d2 100644 --- a/core/services/job/orm_test.go +++ b/core/services/job/orm_test.go @@ -34,13 +34,13 @@ func TestLoadConfigVarsLocalOCR(t *testing.T) { chainConfig := evmtest.NewChainScopedConfig(t, config) jobSpec := &job.OCROracleSpec{} - jobSpec = job.LoadConfigVarsLocalOCR(chainConfig.EVM().OCR(), *jobSpec, chainConfig.OCR()) + jobSpec = job.LoadConfigVarsLocalOCR(chainConfig.EVM().OCR(), *jobSpec, config.OCR()) - require.Equal(t, models.Interval(chainConfig.OCR().ObservationTimeout()), jobSpec.ObservationTimeout) - require.Equal(t, models.Interval(chainConfig.OCR().BlockchainTimeout()), jobSpec.BlockchainTimeout) - require.Equal(t, models.Interval(chainConfig.OCR().ContractSubscribeInterval()), jobSpec.ContractConfigTrackerSubscribeInterval) - require.Equal(t, models.Interval(chainConfig.OCR().ContractPollInterval()), jobSpec.ContractConfigTrackerPollInterval) - require.Equal(t, chainConfig.OCR().CaptureEATelemetry(), jobSpec.CaptureEATelemetry) + require.Equal(t, models.Interval(config.OCR().ObservationTimeout()), jobSpec.ObservationTimeout) + require.Equal(t, models.Interval(config.OCR().BlockchainTimeout()), jobSpec.BlockchainTimeout) + require.Equal(t, models.Interval(config.OCR().ContractSubscribeInterval()), jobSpec.ContractConfigTrackerSubscribeInterval) + require.Equal(t, models.Interval(config.OCR().ContractPollInterval()), jobSpec.ContractConfigTrackerPollInterval) + require.Equal(t, config.OCR().CaptureEATelemetry(), jobSpec.CaptureEATelemetry) require.Equal(t, chainConfig.EVM().OCR().ContractConfirmations(), jobSpec.ContractConfigConfirmations) require.Equal(t, models.Interval(chainConfig.EVM().OCR().DatabaseTimeout()), *jobSpec.DatabaseTimeout) diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index ed2950ac382..26a78a8624e 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -54,17 +54,18 @@ import ( var monitoringEndpoint = telemetry.MonitoringEndpointGenerator(&telemetry.NoopAgent{}) func TestRunner(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} - kb, err := keyStore.OCR().Create() + kb, err := keyStore.OCR().Create(ctx) require.NoError(t, err) kbid := models.MustSha256HashFromHex(kb.ID()) c.OCR.KeyBundleID = &kbid @@ -79,8 +80,7 @@ func TestRunner(t *testing.T) { ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(cltest.Head(10), nil) ethClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(nil, nil) - ctx := testutils.Context(t) - pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) require.NoError(t, pipelineORM.Start(ctx)) t.Cleanup(func() { assert.NoError(t, pipelineORM.Close()) }) btORM := bridges.NewORM(db) @@ -198,7 +198,7 @@ func TestRunner(t *testing.T) { // Reference a different one legacyChains := cltest.NewLegacyChainsWithMockChain(t, nil, config) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 evmChainID = 0 @@ -437,6 +437,7 @@ answer1 [type=median index=0]; }) t.Run("minimal bootstrap", func(t *testing.T) { + ctx := testutils.Context(t) s := ` type = "offchainreporting" schemaVersion = 1 @@ -445,7 +446,7 @@ answer1 [type=median index=0]; evmChainID = "0" ` s = fmt.Sprintf(s, cltest.NewEIP55Address()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &jb) require.NoError(t, err) @@ -454,7 +455,7 @@ answer1 [type=median index=0]; require.NoError(t, err) lggr := logger.TestLogger(t) - _, err = keyStore.P2P().Create() + _, err = keyStore.P2P().Create(ctx) assert.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) servicetest.Run(t, pw) @@ -467,7 +468,7 @@ answer1 [type=median index=0]; monitoringEndpoint, legacyChains, lggr, - config.Database(), + config, servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(testutils.Context(t), jb) @@ -475,11 +476,12 @@ answer1 [type=median index=0]; }) t.Run("test min non-bootstrap", func(t *testing.T) { - kb, err := keyStore.OCR().Create() + ctx := testutils.Context(t) + kb, err := keyStore.OCR().Create(ctx) require.NoError(t, err) s := fmt.Sprintf(minimalNonBootstrapTemplate, cltest.NewEIP55Address(), transmitterAddress.Hex(), kb.ID(), "http://blah.com", "") - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &jb) require.NoError(t, err) @@ -501,7 +503,7 @@ answer1 [type=median index=0]; monitoringEndpoint, legacyChains, lggr, - config.Database(), + config, servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(testutils.Context(t), jb) @@ -510,7 +512,7 @@ answer1 [type=median index=0]; t.Run("test min bootstrap", func(t *testing.T) { s := fmt.Sprintf(minimalBootstrapTemplate, cltest.NewEIP55Address()) - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &jb) require.NoError(t, err) @@ -529,7 +531,7 @@ answer1 [type=median index=0]; monitoringEndpoint, legacyChains, lggr, - config.Database(), + config, servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(testutils.Context(t), jb) @@ -537,6 +539,7 @@ answer1 [type=median index=0]; }) t.Run("test enhanced telemetry service creation", func(t *testing.T) { + ctx := testutils.Context(t) testCases := []struct { jbCaptureEATelemetry bool specCaptureEATelemetry bool @@ -558,11 +561,11 @@ answer1 [type=median index=0]; relayExtenders = evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) legacyChains = evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - kb, err := keyStore.OCR().Create() + kb, err := keyStore.OCR().Create(ctx) require.NoError(t, err) s := fmt.Sprintf(minimalNonBootstrapTemplate, cltest.NewEIP55Address(), transmitterAddress.Hex(), kb.ID(), "http://blah.com", "") - jb, err := ocr.ValidatedOracleSpecToml(legacyChains, s) + jb, err := ocr.ValidatedOracleSpecToml(config, legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &jb) require.NoError(t, err) @@ -584,7 +587,7 @@ answer1 [type=median index=0]; monitoringEndpoint, legacyChains, lggr, - config.Database(), + config, servicetest.Run(t, mailboxtest.NewMonitor(t)), ) @@ -606,8 +609,9 @@ answer1 [type=median index=0]; }) t.Run("test job spec error is created", func(t *testing.T) { + ctx := testutils.Context(t) // Create a keystore with an ocr key bundle and p2p key. - kb, err := keyStore.OCR().Create() + kb, err := keyStore.OCR().Create(ctx) require.NoError(t, err) spec := fmt.Sprintf(ocrJobSpecTemplate, testutils.NewAddress().Hex(), kb.ID(), transmitterAddress.Hex(), fmt.Sprintf(simpleFetchDataSourceTemplate, "blah", true)) jb := makeOCRJobSpecFromToml(t, spec) @@ -628,7 +632,7 @@ answer1 [type=median index=0]; monitoringEndpoint, legacyChains, lggr, - config.Database(), + config, servicetest.Run(t, mailboxtest.NewMonitor(t)), ) services, err := sd.ServicesForSpec(testutils.Context(t), *jb) @@ -636,7 +640,6 @@ answer1 [type=median index=0]; // Return an error getting the contract code. ethClient.On("CodeAt", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("no such code")) - ctx := testutils.Context(t) for _, s := range services { err = s.Start(ctx) require.NoError(t, err) @@ -888,7 +891,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { _ = cltest.CreateJobRunViaExternalInitiatorV2(t, app, jobUUID, *eia, cltest.MustJSONMarshal(t, eiRequest)) - pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(app.GetSqlxDB()) jobORM := NewTestORM(t, app.GetSqlxDB(), pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) @@ -1065,7 +1068,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { t.Run("simulate request from EI -> Core node with erroring callback", func(t *testing.T) { _ = cltest.CreateJobRunViaExternalInitiatorV2(t, app, jobUUID, *eia, cltest.MustJSONMarshal(t, eiRequest)) - pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + pipelineORM := pipeline.NewORM(app.GetSqlxDB(), logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(app.GetSqlxDB()) jobORM := NewTestORM(t, app.GetSqlxDB(), pipelineORM, bridgesORM, app.KeyStore, cfg.Database()) diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index 3d30a3190b3..8024424226c 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -78,7 +78,7 @@ type ( // non-db side effects. This is required in order to guarantee mutual atomicity between // all tasks intended to happen during job deletion. For the same reason, the job will // not show up in the db within OnDeleteJob(), even though it is still actively running. - OnDeleteJob(ctx context.Context, jb Job, q pg.Queryer) error + OnDeleteJob(ctx context.Context, jb Job) error } activeJob struct { @@ -340,7 +340,7 @@ func (js *spawner) DeleteJob(jobID int32, qopts ...pg.QOpt) error { // we know the DELETE will succeed. The DELETE will be finalized only if all db transactions in OnDeleteJob() // succeed. If either of those fails, the job will not be stopped and everything will be rolled back. lggr.Debugw("Callback: OnDeleteJob") - err = aj.delegate.OnDeleteJob(ctx, aj.spec, tx) + err = aj.delegate.OnDeleteJob(ctx, aj.spec) if err != nil { return err } @@ -395,7 +395,9 @@ func (n *NullDelegate) ServicesForSpec(ctx context.Context, spec Job) (s []Servi return } -func (n *NullDelegate) BeforeJobCreated(spec Job) {} -func (n *NullDelegate) AfterJobCreated(spec Job) {} -func (n *NullDelegate) BeforeJobDeleted(spec Job) {} -func (n *NullDelegate) OnDeleteJob(ctx context.Context, spec Job, q pg.Queryer) error { return nil } +func (n *NullDelegate) BeforeJobCreated(spec Job) {} +func (n *NullDelegate) AfterJobCreated(spec Job) {} +func (n *NullDelegate) BeforeJobDeleted(spec Job) {} +func (n *NullDelegate) OnDeleteJob(context.Context, Job) error { + return nil +} diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index d2e7a80d5d4..ae8ffaa2161 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/capabilities" @@ -34,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/plugins" @@ -69,20 +69,21 @@ type relayGetter struct { r *evmrelayer.Relayer } -func (g *relayGetter) Get(id relay.ID) (loop.Relayer, error) { +func (g *relayGetter) Get(id types.RelayID) (loop.Relayer, error) { return evmrelayer.NewLoopRelayServerAdapter(g.r, g.e), nil } func TestSpawner_CreateJobDeleteJob(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() - require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) - require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) + require.NoError(t, keyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, keyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) + require.NoError(t, keyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) _, address := cltest.MustInsertRandomKey(t, ethKeyStore) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}) @@ -100,7 +101,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) t.Run("should respect its dependents", func(t *testing.T) { lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) a := utils.NewDependentAwaiter() a.AddDependents(1) spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{}, db, lggr, []utils.DependentAwaiter{a}) @@ -123,7 +124,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobB := makeOCRJobSpec(t, address, bridge.Name.String(), bridge2.Name.String()) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) eventuallyA := cltest.NewAwaiter() serviceA1 := mocks.NewServiceCtx(t) @@ -131,7 +132,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA1.On("Start", mock.Anything).Return(nil).Once() serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyA.ItHappened() }) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) + dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, make(chan struct{}), dA} eventuallyB := cltest.NewAwaiter() @@ -139,7 +140,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceB2 := mocks.NewServiceCtx(t) serviceB1.On("Start", mock.Anything).Return(nil).Once() serviceB2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyB.ItHappened() }) - dB := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) + dB := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateB := &delegate{jobB.Type, []job.ServiceCtx{serviceB1, serviceB2}, 0, make(chan struct{}), dB} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -188,9 +189,9 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventually.ItHappened() }) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) + d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ jobA.Type: delegateA, @@ -222,9 +223,9 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyStart.ItHappened() }) lggr := logger.TestLogger(t) - orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) + d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ jobA.Type: delegateA, @@ -300,7 +301,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobOCR2VRF := makeOCR2VRFJobSpec(t, keyStore, config, address, chain.ID(), 2) - orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) + orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore, config.Database()) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }, func(loopId string) {}) diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 679ccf3053d..184a61e1e1a 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -9,16 +9,21 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) // To make sure Delegate struct implements job.Delegate interface var _ job.Delegate = (*Delegate)(nil) +type DelegateConfig interface { + Keeper() config.Keeper +} + type Delegate struct { + cfg DelegateConfig logger logger.Logger db *sqlx.DB jrm job.ORM @@ -29,6 +34,7 @@ type Delegate struct { // NewDelegate is the constructor of Delegate func NewDelegate( + cfg DelegateConfig, db *sqlx.DB, jrm job.ORM, pr pipeline.Runner, @@ -37,6 +43,7 @@ func NewDelegate( mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ + cfg: cfg, logger: logger, db: db, jrm: jrm, @@ -51,10 +58,10 @@ func (d *Delegate) JobType() job.Type { return job.Keeper } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { @@ -95,7 +102,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services } } - keeper := chain.Config().Keeper() + keeper := d.cfg.Keeper() registry := keeper.Registry() registrySynchronizer := NewRegistrySynchronizer(RegistrySynchronizerOptions{ Job: spec, @@ -118,7 +125,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services chain.HeadBroadcaster(), chain.GasEstimator(), svcLogger, - chain.Config().Keeper(), + d.cfg.Keeper(), effectiveKeeperAddress, ) diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index 49073c8de56..08699d3d835 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -175,6 +175,7 @@ func TestKeeperEthIntegration(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) g := gomega.NewWithT(t) // setup node key @@ -249,12 +250,12 @@ func TestKeeperEthIntegration(t *testing.T) { korm := keeper.NewORM(db, logger.TestLogger(t)) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, backend.Backend(), nodeKey) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // create job regAddrEIP55 := evmtypes.EIP55AddressFromAddress(regAddr) job := cltest.MustInsertKeeperJob(t, db, korm, nodeAddressEIP55, regAddrEIP55) - err = app.JobSpawner().StartService(testutils.Context(t), job) + err = app.JobSpawner().StartService(ctx, job) require.NoError(t, err) // keeper job is triggered and payload is received @@ -311,7 +312,7 @@ func TestKeeperEthIntegration(t *testing.T) { cltest.AssertRecordEventually(t, app.GetSqlxDB(), ®istry, fmt.Sprintf("SELECT * FROM keeper_registries WHERE id = %d", registry.ID), func() bool { return registry.KeeperIndex == -1 }) - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) // Since we set grace period to 0, we can have more than 1 pipeline run per perform // This happens in case we start a pipeline run before previous perform tx is committed to chain @@ -481,6 +482,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { func TestMaxPerformDataSize(t *testing.T) { t.Parallel() t.Run("max_perform_data_size_test", func(t *testing.T) { + ctx := testutils.Context(t) maxPerformDataSize := 1000 // Will be set as config override g := gomega.NewWithT(t) @@ -552,12 +554,12 @@ func TestMaxPerformDataSize(t *testing.T) { korm := keeper.NewORM(db, logger.TestLogger(t)) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, backend.Backend(), nodeKey) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // create job regAddrEIP55 := evmtypes.EIP55AddressFromAddress(regAddr) job := cltest.MustInsertKeeperJob(t, db, korm, nodeAddressEIP55, regAddrEIP55) - err = app.JobSpawner().StartService(testutils.Context(t), job) + err = app.JobSpawner().StartService(ctx, job) require.NoError(t, err) // keeper job is triggered diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index 1e5d927fe2f..439970b381b 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -14,16 +14,15 @@ import ( "github.com/jmoiron/sqlx" - evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" @@ -36,12 +35,11 @@ var ( func setupKeeperDB(t *testing.T) ( *sqlx.DB, - evmconfig.ChainScopedConfig, + chainlink.GeneralConfig, *keeper.ORM, ) { - gcfg := configtest.NewGeneralConfig(t, nil) + cfg := configtest.NewGeneralConfig(t, nil) db := pgtest.NewSqlxDB(t) - cfg := evmtest.NewChainScopedConfig(t, gcfg) orm := keeper.NewORM(db, logger.TestLogger(t)) return db, cfg, orm } @@ -76,8 +74,8 @@ func assertLastRunHeight(t *testing.T, db *sqlx.DB, upkeep keeper.UpkeepRegistra func TestKeeperDB_Registries(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) @@ -90,8 +88,8 @@ func TestKeeperDB_Registries(t *testing.T) { func TestKeeperDB_RegistryByContractAddress(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) @@ -104,8 +102,8 @@ func TestKeeperDB_RegistryByContractAddress(t *testing.T) { func TestKeeperDB_UpsertUpkeep(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := keeper.UpkeepRegistration{ @@ -140,8 +138,8 @@ func TestKeeperDB_UpsertUpkeep(t *testing.T) { func TestKeeperDB_BatchDeleteUpkeepsForJob(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, job := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) @@ -167,8 +165,8 @@ func TestKeeperDB_BatchDeleteUpkeepsForJob(t *testing.T) { func TestKeeperDB_EligibleUpkeeps_Shuffle(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() blockheight := int64(63) gracePeriod := int64(10) @@ -198,8 +196,8 @@ func TestKeeperDB_EligibleUpkeeps_Shuffle(t *testing.T) { func TestKeeperDB_NewEligibleUpkeeps_GracePeriod(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 2, 20) @@ -226,8 +224,8 @@ func TestKeeperDB_NewEligibleUpkeeps_GracePeriod(t *testing.T) { func TestKeeperDB_EligibleUpkeeps_TurnsRandom(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 3, 10) @@ -270,8 +268,8 @@ func TestKeeperDB_EligibleUpkeeps_TurnsRandom(t *testing.T) { func TestKeeperDB_NewEligibleUpkeeps_SkipIfLastPerformedByCurrentKeeper(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 2, 20) @@ -293,8 +291,8 @@ func TestKeeperDB_NewEligibleUpkeeps_SkipIfLastPerformedByCurrentKeeper(t *testi func TestKeeperDB_NewEligibleUpkeeps_CoverBuddy(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 1, 2, 20) @@ -318,8 +316,8 @@ func TestKeeperDB_NewEligibleUpkeeps_CoverBuddy(t *testing.T) { func TestKeeperDB_NewEligibleUpkeeps_FirstTurn(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 2, 20) @@ -340,8 +338,8 @@ func TestKeeperDB_NewEligibleUpkeeps_FirstTurn(t *testing.T) { func TestKeeperDB_NewEligibleUpkeeps_FiltersByRegistry(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry1, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) registry2, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) @@ -365,8 +363,8 @@ func TestKeeperDB_NewEligibleUpkeeps_FiltersByRegistry(t *testing.T) { func TestKeeperDB_AllUpkeepIDsForRegistry(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeepIDs, err := orm.AllUpkeepIDsForRegistry(ctx, registry.ID) @@ -394,8 +392,8 @@ func TestKeeperDB_AllUpkeepIDsForRegistry(t *testing.T) { func TestKeeperDB_UpdateUpkeepLastKeeperIndex(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, j := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, registry) @@ -409,8 +407,8 @@ func TestKeeperDB_UpdateUpkeepLastKeeperIndex(t *testing.T) { func TestKeeperDB_NewSetLastRunInfoForUpkeepOnJob(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db, config, orm := setupKeeperDB(t) - ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() + db, _, orm := setupKeeperDB(t) + ethKeyStore := cltest.NewKeyStore(t, db).Eth() registry, j := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, registry) diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index 24a6a7288a7..61482208e5c 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -201,6 +201,7 @@ func Test_RegistrySynchronizer1_1_FullSync(t *testing.T) { } func Test_RegistrySynchronizer1_1_ConfigSetLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_1) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -235,11 +236,11 @@ func Test_RegistrySynchronizer1_1_ConfigSetLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.BlockCountPerTurn == 40 @@ -248,6 +249,7 @@ func Test_RegistrySynchronizer1_1_ConfigSetLog(t *testing.T) { } func Test_RegistrySynchronizer1_1_KeepersUpdatedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_1) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -281,11 +283,11 @@ func Test_RegistrySynchronizer1_1_KeepersUpdatedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.NumKeepers == 2 @@ -293,6 +295,7 @@ func Test_RegistrySynchronizer1_1_KeepersUpdatedLog(t *testing.T) { cltest.AssertCount(t, db, "keeper_registries", 1) } func Test_RegistrySynchronizer1_1_UpkeepCanceledLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_1) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -320,16 +323,17 @@ func Test_RegistrySynchronizer1_1_UpkeepCanceledLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_1_UpkeepRegisteredLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_1) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -360,16 +364,17 @@ func Test_RegistrySynchronizer1_1_UpkeepRegisteredLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_1_UpkeepPerformedLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_1) @@ -401,11 +406,11 @@ func Test_RegistrySynchronizer1_1_UpkeepPerformedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(func() int64 { var upkeep keeper.UpkeepRegistration diff --git a/core/services/keeper/registry1_2_synchronizer_test.go b/core/services/keeper/registry1_2_synchronizer_test.go index 23e6c0355ec..a62e27b8759 100644 --- a/core/services/keeper/registry1_2_synchronizer_test.go +++ b/core/services/keeper/registry1_2_synchronizer_test.go @@ -220,6 +220,7 @@ func Test_RegistrySynchronizer1_2_FullSync(t *testing.T) { } func Test_RegistrySynchronizer1_2_ConfigSetLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -258,11 +259,11 @@ func Test_RegistrySynchronizer1_2_ConfigSetLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.BlockCountPerTurn == 40 @@ -271,6 +272,7 @@ func Test_RegistrySynchronizer1_2_ConfigSetLog(t *testing.T) { } func Test_RegistrySynchronizer1_2_KeepersUpdatedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -308,11 +310,11 @@ func Test_RegistrySynchronizer1_2_KeepersUpdatedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.NumKeepers == 2 @@ -321,6 +323,7 @@ func Test_RegistrySynchronizer1_2_KeepersUpdatedLog(t *testing.T) { } func Test_RegistrySynchronizer1_2_UpkeepCanceledLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -349,16 +352,17 @@ func Test_RegistrySynchronizer1_2_UpkeepCanceledLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_2_UpkeepRegisteredLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -390,16 +394,17 @@ func Test_RegistrySynchronizer1_2_UpkeepRegisteredLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_2_UpkeepPerformedLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) @@ -432,11 +437,11 @@ func Test_RegistrySynchronizer1_2_UpkeepPerformedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(func() int64 { var upkeep keeper.UpkeepRegistration @@ -454,6 +459,7 @@ func Test_RegistrySynchronizer1_2_UpkeepPerformedLog(t *testing.T) { } func Test_RegistrySynchronizer1_2_UpkeepGasLimitSetLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) @@ -496,16 +502,17 @@ func Test_RegistrySynchronizer1_2_UpkeepGasLimitSetLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(getExecuteGas, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(uint32(4_000_000))) } func Test_RegistrySynchronizer1_2_UpkeepReceivedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -537,16 +544,17 @@ func Test_RegistrySynchronizer1_2_UpkeepReceivedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_2_UpkeepMigratedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_2) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -575,11 +583,11 @@ func Test_RegistrySynchronizer1_2_UpkeepMigratedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index 2b5900ac189..7ebbbc25469 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -225,6 +225,7 @@ func Test_RegistrySynchronizer1_3_FullSync(t *testing.T) { } func Test_RegistrySynchronizer1_3_ConfigSetLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -263,11 +264,11 @@ func Test_RegistrySynchronizer1_3_ConfigSetLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.BlockCountPerTurn == 40 @@ -276,6 +277,7 @@ func Test_RegistrySynchronizer1_3_ConfigSetLog(t *testing.T) { } func Test_RegistrySynchronizer1_3_KeepersUpdatedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -313,11 +315,11 @@ func Test_RegistrySynchronizer1_3_KeepersUpdatedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.AssertRecordEventually(t, db, ®istry, fmt.Sprintf(`SELECT * FROM keeper_registries WHERE id = %d`, registry.ID), func() bool { return registry.NumKeepers == 2 @@ -326,6 +328,7 @@ func Test_RegistrySynchronizer1_3_KeepersUpdatedLog(t *testing.T) { } func Test_RegistrySynchronizer1_3_UpkeepCanceledLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -354,16 +357,17 @@ func Test_RegistrySynchronizer1_3_UpkeepCanceledLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_3_UpkeepRegisteredLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -395,16 +399,17 @@ func Test_RegistrySynchronizer1_3_UpkeepRegisteredLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_3_UpkeepPerformedLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) @@ -437,11 +442,11 @@ func Test_RegistrySynchronizer1_3_UpkeepPerformedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(func() int64 { var upkeep keeper.UpkeepRegistration @@ -459,6 +464,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPerformedLog(t *testing.T) { } func Test_RegistrySynchronizer1_3_UpkeepGasLimitSetLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) @@ -501,16 +507,17 @@ func Test_RegistrySynchronizer1_3_UpkeepGasLimitSetLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(getExecuteGas, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(uint32(4_000_000))) } func Test_RegistrySynchronizer1_3_UpkeepReceivedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -542,16 +549,17 @@ func Test_RegistrySynchronizer1_3_UpkeepReceivedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_3_UpkeepMigratedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -580,17 +588,18 @@ func Test_RegistrySynchronizer1_3_UpkeepMigratedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) // race condition: "wait for count" cltest.WaitForCount(t, db, "upkeep_registrations", 2) } func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T) { + ctx := testutils.Context(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) contractAddress := job.KeeperSpec.ContractAddress.Address() @@ -620,11 +629,11 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T logBroadcast.On("DecodedLog").Return(&log) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 2) @@ -635,11 +644,11 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T logBroadcast.On("DecodedLog").Return(&unpausedlog) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) cltest.WaitForCount(t, db, "upkeep_registrations", 3) var upkeep keeper.UpkeepRegistration @@ -657,6 +666,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T } func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { + ctx := testutils.Context(t) g := gomega.NewWithT(t) db, synchronizer, ethMock, lb, job := setupRegistrySync(t, keeper.RegistryVersion_1_3) @@ -694,11 +704,11 @@ func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { logBroadcast.On("DecodedLog").Return(&updatedLog) logBroadcast.On("RawLog").Return(rawLog) logBroadcast.On("String").Maybe().Return("") - lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) // Do the thing - synchronizer.HandleLog(logBroadcast) + synchronizer.HandleLog(ctx, logBroadcast) g.Eventually(func() []byte { var upkeep keeper.UpkeepRegistration diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index c97d3c0c92c..2726c9a754d 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -40,7 +40,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( cfg := configtest.NewGeneralConfig(t, nil) korm := keeper.NewORM(db, logger.TestLogger(t)) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) lbMock := logmocks.NewBroadcaster(t) lbMock.On("AddDependents", 1).Maybe() j := cltest.MustInsertKeeperJob(t, db, korm, cltest.NewEIP55Address(), cltest.NewEIP55Address()) diff --git a/core/services/keeper/registry_synchronizer_log_listener.go b/core/services/keeper/registry_synchronizer_log_listener.go index 099d01d27f6..93ff2e9e950 100644 --- a/core/services/keeper/registry_synchronizer_log_listener.go +++ b/core/services/keeper/registry_synchronizer_log_listener.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "reflect" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -10,7 +11,7 @@ func (rs *RegistrySynchronizer) JobID() int32 { return rs.job.ID } -func (rs *RegistrySynchronizer) HandleLog(broadcast log.Broadcast) { +func (rs *RegistrySynchronizer) HandleLog(ctx context.Context, broadcast log.Broadcast) { eventLog := broadcast.DecodedLog() if eventLog == nil || reflect.ValueOf(eventLog).IsNil() { rs.logger.Panicf("HandleLog: ignoring nil value, type: %T", broadcast) diff --git a/core/services/keeper/registry_synchronizer_process_logs.go b/core/services/keeper/registry_synchronizer_process_logs.go index 0a0e1613c95..a1bdcd8db0b 100644 --- a/core/services/keeper/registry_synchronizer_process_logs.go +++ b/core/services/keeper/registry_synchronizer_process_logs.go @@ -85,7 +85,7 @@ func (rs *RegistrySynchronizer) processLogs(ctx context.Context) { rs.logger.Error(err) } - err = rs.logBroadcaster.MarkConsumed(ctx, broadcast) + err = rs.logBroadcaster.MarkConsumed(ctx, nil, broadcast) if err != nil { rs.logger.Error(errors.Wrapf(err, "unable to mark %T log as consumed, log: %v", broadcast.RawLog(), broadcast.String())) } diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 10995ec3c0d..ec23331f904 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -75,7 +75,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain } }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ethClient := evmtest.NewEthClientMock(t) ethClient.On("ConfiguredChainID").Return(cfg.EVMConfigs()[0].ChainID.ToInt()).Maybe() ethClient.On("IsL2").Return(false).Maybe() @@ -89,7 +89,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain registry, jb := cltest.MustInsertKeeperRegistry(t, db, orm, keyStore.Eth(), 0, 1, 20) lggr := logger.TestLogger(t) - executer := keeper.NewUpkeepExecuter(jb, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), jb.KeeperSpec.FromAddress.Address()) + executer := keeper.NewUpkeepExecuter(jb, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, cfg.Keeper(), jb.KeeperSpec.FromAddress.Address()) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, registry) servicetest.Run(t, executer) return db, cfg, ethClient, executer, registry, upkeep, jb, jpv2, txm, keyStore, ch, orm @@ -262,14 +262,14 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { }) t.Run("errors if submission chain not found", func(t *testing.T) { - db, _, ethMock, _, _, _, _, jpv2, _, keyStore, ch, orm := setup(t, mockEstimator(t), nil) + db, cfg, ethMock, _, _, _, _, jpv2, _, keyStore, ch, orm := setup(t, mockEstimator(t), nil) registry, jb := cltest.MustInsertKeeperRegistry(t, db, orm, keyStore.Eth(), 0, 1, 20) // change chain ID to non-configured chain jb.KeeperSpec.EVMChainID = (*ubig.Big)(big.NewInt(999)) cltest.MustInsertUpkeepForRegistry(t, db, registry) lggr := logger.TestLogger(t) - executer := keeper.NewUpkeepExecuter(jb, orm, jpv2.Pr, ethMock, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), jb.KeeperSpec.FromAddress.Address()) + executer := keeper.NewUpkeepExecuter(jb, orm, jpv2.Pr, ethMock, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, cfg.Keeper(), jb.KeeperSpec.FromAddress.Address()) err := executer.Start(testutils.Context(t)) require.NoError(t, err) head := newHead() diff --git a/core/services/keystore/cosmos.go b/core/services/keystore/cosmos.go index e3549fdb932..76fc5f39816 100644 --- a/core/services/keystore/cosmos.go +++ b/core/services/keystore/cosmos.go @@ -15,12 +15,12 @@ import ( type Cosmos interface { Get(id string) (cosmoskey.Key, error) GetAll() ([]cosmoskey.Key, error) - Create() (cosmoskey.Key, error) - Add(key cosmoskey.Key) error - Delete(id string) (cosmoskey.Key, error) - Import(keyJSON []byte, password string) (cosmoskey.Key, error) + Create(ctx context.Context) (cosmoskey.Key, error) + Add(ctx context.Context, key cosmoskey.Key) error + Delete(ctx context.Context, id string) (cosmoskey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (cosmoskey.Key, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } type cosmos struct { @@ -56,17 +56,17 @@ func (ks *cosmos) GetAll() (keys []cosmoskey.Key, _ error) { return keys, nil } -func (ks *cosmos) Create() (cosmoskey.Key, error) { +func (ks *cosmos) Create(ctx context.Context) (cosmoskey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { return cosmoskey.Key{}, ErrLocked } key := cosmoskey.New() - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *cosmos) Add(key cosmoskey.Key) error { +func (ks *cosmos) Add(ctx context.Context, key cosmoskey.Key) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -75,10 +75,10 @@ func (ks *cosmos) Add(key cosmoskey.Key) error { if _, found := ks.keyRing.Cosmos[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *cosmos) Delete(id string) (cosmoskey.Key, error) { +func (ks *cosmos) Delete(ctx context.Context, id string) (cosmoskey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -88,11 +88,11 @@ func (ks *cosmos) Delete(id string) (cosmoskey.Key, error) { if err != nil { return cosmoskey.Key{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) { +func (ks *cosmos) Import(ctx context.Context, keyJSON []byte, password string) (cosmoskey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -105,7 +105,7 @@ func (ks *cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) if _, found := ks.keyRing.Cosmos[key.ID()]; found { return cosmoskey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *cosmos) Export(id string, password string) ([]byte, error) { @@ -121,7 +121,7 @@ func (ks *cosmos) Export(id string, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -func (ks *cosmos) EnsureKey() error { +func (ks *cosmos) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -136,7 +136,7 @@ func (ks *cosmos) EnsureKey() error { ks.logger.Infof("Created Cosmos key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } func (ks *cosmos) getByID(id string) (cosmoskey.Key, error) { diff --git a/core/services/keystore/cosmos_test.go b/core/services/keystore/cosmos_test.go index 30c669f7545..cad6dd67654 100644 --- a/core/services/keystore/cosmos_test.go +++ b/core/services/keystore/cosmos_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -8,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" @@ -16,15 +17,15 @@ import ( func Test_CosmosKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.Cosmos() reset := func() { + ctx := context.Background() // Executed during cleanup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -42,7 +43,8 @@ func Test_CosmosKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -51,21 +53,22 @@ func Test_CosmosKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) _, err = ks.Export("non-existent", cltest.Password) assert.Error(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) - _, err = ks.Import(exportJSON, cltest.Password) + _, err = ks.Import(ctx, exportJSON, cltest.Password) assert.Error(t, err) - _, err = ks.Import([]byte(""), cltest.Password) + _, err = ks.Import(ctx, []byte(""), cltest.Password) assert.Error(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -75,17 +78,18 @@ func Test_CosmosKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey := cosmoskey.New() - err := ks.Add(newKey) + err := ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -96,10 +100,11 @@ func Test_CosmosKeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKey() + ctx := testutils.Context(t) + err := ks.EnsureKey(ctx) assert.NoError(t, err) - err = ks.EnsureKey() + err = ks.EnsureKey(ctx) assert.NoError(t, err) keys, err := ks.GetAll() diff --git a/core/services/keystore/csa.go b/core/services/keystore/csa.go index 01491b85b35..21b530c0650 100644 --- a/core/services/keystore/csa.go +++ b/core/services/keystore/csa.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" @@ -17,12 +18,12 @@ var ErrCSAKeyExists = errors.New("can only have 1 CSA key") type CSA interface { Get(id string) (csakey.KeyV2, error) GetAll() ([]csakey.KeyV2, error) - Create() (csakey.KeyV2, error) - Add(key csakey.KeyV2) error - Delete(id string) (csakey.KeyV2, error) - Import(keyJSON []byte, password string) (csakey.KeyV2, error) + Create(ctx context.Context) (csakey.KeyV2, error) + Add(ctx context.Context, key csakey.KeyV2) error + Delete(ctx context.Context, id string) (csakey.KeyV2, error) + Import(ctx context.Context, keyJSON []byte, password string) (csakey.KeyV2, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } type csa struct { @@ -58,7 +59,7 @@ func (ks *csa) GetAll() (keys []csakey.KeyV2, _ error) { return keys, nil } -func (ks *csa) Create() (csakey.KeyV2, error) { +func (ks *csa) Create(ctx context.Context) (csakey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -74,10 +75,10 @@ func (ks *csa) Create() (csakey.KeyV2, error) { if err != nil { return csakey.KeyV2{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *csa) Add(key csakey.KeyV2) error { +func (ks *csa) Add(ctx context.Context, key csakey.KeyV2) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -86,10 +87,10 @@ func (ks *csa) Add(key csakey.KeyV2) error { if len(ks.keyRing.CSA) > 0 { return ErrCSAKeyExists } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *csa) Delete(id string) (csakey.KeyV2, error) { +func (ks *csa) Delete(ctx context.Context, id string) (csakey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -100,12 +101,12 @@ func (ks *csa) Delete(id string) (csakey.KeyV2, error) { return csakey.KeyV2{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *csa) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { +func (ks *csa) Import(ctx context.Context, keyJSON []byte, password string) (csakey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -118,7 +119,7 @@ func (ks *csa) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { if _, found := ks.keyRing.CSA[key.ID()]; found { return csakey.KeyV2{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *csa) Export(id string, password string) ([]byte, error) { @@ -135,7 +136,7 @@ func (ks *csa) Export(id string, password string) ([]byte, error) { } // EnsureKey verifies whether the CSA key has been seeded, if not, it creates it. -func (ks *csa) EnsureKey() error { +func (ks *csa) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -153,7 +154,7 @@ func (ks *csa) EnsureKey() error { ks.logger.Infof("Created CSA key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } func (ks *csa) getByID(id string) (csakey.KeyV2, error) { diff --git a/core/services/keystore/csa_test.go b/core/services/keystore/csa_test.go index b6dfb009593..84d79798011 100644 --- a/core/services/keystore/csa_test.go +++ b/core/services/keystore/csa_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "fmt" "testing" @@ -9,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -17,15 +18,15 @@ import ( func Test_CSAKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.CSA() reset := func() { + ctx := context.Background() // Executed on cleanup _, err := db.Exec("DELETE FROM encrypted_key_rings") require.NoError(t, err) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -43,14 +44,16 @@ func Test_CSAKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) require.Equal(t, key, retrievedKey) t.Run("prevents creating more than one key", func(t *testing.T) { - k, err2 := ks.Create() + ctx := testutils.Context(t) + k, err2 := ks.Create(ctx) assert.Zero(t, k) assert.Error(t, err2) @@ -60,15 +63,16 @@ func Test_CSAKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -76,7 +80,7 @@ func Test_CSAKeyStore_E2E(t *testing.T) { require.Equal(t, importedKey, retrievedKey) t.Run("prevents importing more than one key", func(t *testing.T) { - k, err2 := ks.Import(exportJSON, cltest.Password) + k, err2 := ks.Import(testutils.Context(t), exportJSON, cltest.Password) assert.Zero(t, k) assert.Error(t, err2) @@ -84,7 +88,7 @@ func Test_CSAKeyStore_E2E(t *testing.T) { }) t.Run("fails to import malformed key", func(t *testing.T) { - k, err2 := ks.Import([]byte(""), cltest.Password) + k, err2 := ks.Import(testutils.Context(t), []byte(""), cltest.Password) assert.Zero(t, k) assert.Error(t, err2) @@ -100,14 +104,15 @@ func Test_CSAKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := csakey.NewV2() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -116,17 +121,18 @@ func Test_CSAKeyStore_E2E(t *testing.T) { require.Error(t, err) t.Run("prevents adding more than one key", func(t *testing.T) { - err = ks.Add(newKey) + ctx := testutils.Context(t) + err = ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) assert.True(t, errors.Is(err, keystore.ErrCSAKeyExists)) }) t.Run("fails to delete non-existent key", func(t *testing.T) { - k, err2 := ks.Delete("non-existent") + k, err2 := ks.Delete(testutils.Context(t), "non-existent") assert.Zero(t, k) assert.Error(t, err2) @@ -135,13 +141,14 @@ func Test_CSAKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key/ensures it already exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := csakey.NewV2() assert.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.NoError(t, err) - err = keyStore.CSA().EnsureKey() + err = keyStore.CSA().EnsureKey(ctx) assert.NoError(t, err) keys, err2 := ks.GetAll() assert.NoError(t, err2) @@ -154,12 +161,13 @@ func Test_CSAKeyStore_E2E(t *testing.T) { t.Run("auto creates a key if it doesn't exists when trying to ensure it already exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) keys, err := ks.GetAll() assert.NoError(t, err) assert.Equal(t, 0, len(keys)) - err = keyStore.CSA().EnsureKey() + err = keyStore.CSA().EnsureKey(ctx) assert.NoError(t, err) keys, err = ks.GetAll() diff --git a/core/services/keystore/dkgencrypt.go b/core/services/keystore/dkgencrypt.go index c5d02034dad..15d0ae8b24d 100644 --- a/core/services/keystore/dkgencrypt.go +++ b/core/services/keystore/dkgencrypt.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" @@ -14,12 +15,12 @@ import ( type DKGEncrypt interface { Get(id string) (dkgencryptkey.Key, error) GetAll() ([]dkgencryptkey.Key, error) - Create() (dkgencryptkey.Key, error) - Add(key dkgencryptkey.Key) error - Delete(id string) (dkgencryptkey.Key, error) - Import(keyJSON []byte, password string) (dkgencryptkey.Key, error) + Create(ctx context.Context) (dkgencryptkey.Key, error) + Add(ctx context.Context, key dkgencryptkey.Key) error + Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } type dkgEncrypt struct { @@ -35,17 +36,17 @@ func newDKGEncryptKeyStore(km *keyManager) *dkgEncrypt { var _ DKGEncrypt = &dkgEncrypt{} // Add implements DKGEncrypt -func (d *dkgEncrypt) Add(key dkgencryptkey.Key) error { +func (d *dkgEncrypt) Add(ctx context.Context, key dkgencryptkey.Key) error { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { return ErrLocked } - return d.safeAddKey(key) + return d.safeAddKey(ctx, key) } // Create implements DKGEncrypt -func (d *dkgEncrypt) Create() (dkgencryptkey.Key, error) { +func (d *dkgEncrypt) Create(ctx context.Context) (dkgencryptkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -55,11 +56,11 @@ func (d *dkgEncrypt) Create() (dkgencryptkey.Key, error) { if err != nil { return dkgencryptkey.Key{}, errors.Wrap(err, "dkgencryptkey.New()") } - return key, d.safeAddKey(key) + return key, d.safeAddKey(ctx, key) } // Delete implements DKGEncrypt -func (d *dkgEncrypt) Delete(id string) (dkgencryptkey.Key, error) { +func (d *dkgEncrypt) Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -70,12 +71,12 @@ func (d *dkgEncrypt) Delete(id string) (dkgencryptkey.Key, error) { return dkgencryptkey.Key{}, err } - err = d.safeRemoveKey(key) + err = d.safeRemoveKey(ctx, key) return key, errors.Wrap(err, "safe remove key") } // EnsureKey implements DKGEncrypt -func (d *dkgEncrypt) EnsureKey() error { +func (d *dkgEncrypt) EnsureKey(ctx context.Context) error { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -92,7 +93,7 @@ func (d *dkgEncrypt) EnsureKey() error { d.logger.Infof("Created DKGEncrypt key with ID %s", key.ID()) - return d.safeAddKey(key) + return d.safeAddKey(ctx, key) } // Export implements DKGEncrypt @@ -133,7 +134,7 @@ func (d *dkgEncrypt) GetAll() (keys []dkgencryptkey.Key, err error) { } // Import implements DKGEncrypt -func (d *dkgEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key, error) { +func (d *dkgEncrypt) Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -147,7 +148,7 @@ func (d *dkgEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key, if err == nil { return dkgencryptkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, d.keyManager.safeAddKey(key) + return key, d.keyManager.safeAddKey(ctx, key) } // caller must hold lock diff --git a/core/services/keystore/dkgencrypt_test.go b/core/services/keystore/dkgencrypt_test.go index 36f48f9c2b4..4856473a0df 100644 --- a/core/services/keystore/dkgencrypt_test.go +++ b/core/services/keystore/dkgencrypt_test.go @@ -1,13 +1,14 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" @@ -15,18 +16,18 @@ import ( func Test_DKGEncryptKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.DKGEncrypt() assert.NotNil(t, ks) reset := func() { + ctx := context.Background() // Executed on cleanup _, err := db.Exec("DELETE FROM encrypted_key_rings") require.NoError(t, err) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -44,7 +45,8 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -53,15 +55,16 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -71,14 +74,15 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := dkgencryptkey.New() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -89,13 +93,14 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key/ensures it already exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := dkgencryptkey.New() assert.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.NoError(t, err) - err = keyStore.DKGEncrypt().EnsureKey() + err = keyStore.DKGEncrypt().EnsureKey(ctx) assert.NoError(t, err) keys, err2 := ks.GetAll() assert.NoError(t, err2) @@ -107,12 +112,13 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("auto creates a key if it doesn't exists when trying to ensure it already exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) keys, err := ks.GetAll() assert.NoError(t, err) assert.Equal(t, 0, len(keys)) - err = keyStore.DKGEncrypt().EnsureKey() + err = keyStore.DKGEncrypt().EnsureKey(ctx) assert.NoError(t, err) keys, err = ks.GetAll() diff --git a/core/services/keystore/dkgsign.go b/core/services/keystore/dkgsign.go index e609b441831..385323fc0fa 100644 --- a/core/services/keystore/dkgsign.go +++ b/core/services/keystore/dkgsign.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" @@ -14,12 +15,12 @@ import ( type DKGSign interface { Get(id string) (dkgsignkey.Key, error) GetAll() ([]dkgsignkey.Key, error) - Create() (dkgsignkey.Key, error) - Add(key dkgsignkey.Key) error - Delete(id string) (dkgsignkey.Key, error) - Import(keyJSON []byte, password string) (dkgsignkey.Key, error) + Create(ctx context.Context) (dkgsignkey.Key, error) + Add(ctx context.Context, key dkgsignkey.Key) error + Delete(ctx context.Context, id string) (dkgsignkey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } type dkgSign struct { @@ -35,17 +36,17 @@ func newDKGSignKeyStore(km *keyManager) *dkgSign { var _ DKGSign = &dkgSign{} // Add implements DKGSign -func (d *dkgSign) Add(key dkgsignkey.Key) error { +func (d *dkgSign) Add(ctx context.Context, key dkgsignkey.Key) error { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { return ErrLocked } - return d.safeAddKey(key) + return d.safeAddKey(ctx, key) } // Create implements DKGSign -func (d *dkgSign) Create() (dkgsignkey.Key, error) { +func (d *dkgSign) Create(ctx context.Context) (dkgsignkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -55,11 +56,11 @@ func (d *dkgSign) Create() (dkgsignkey.Key, error) { if err != nil { return dkgsignkey.Key{}, errors.Wrap(err, "dkgsignkey New()") } - return key, d.safeAddKey(key) + return key, d.safeAddKey(ctx, key) } // Delete implements DKGSign -func (d *dkgSign) Delete(id string) (dkgsignkey.Key, error) { +func (d *dkgSign) Delete(ctx context.Context, id string) (dkgsignkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -70,12 +71,12 @@ func (d *dkgSign) Delete(id string) (dkgsignkey.Key, error) { return dkgsignkey.Key{}, err } - err = d.safeRemoveKey(key) + err = d.safeRemoveKey(ctx, key) return key, errors.Wrap(err, "safe remove key") } // EnsureKey implements DKGSign -func (d *dkgSign) EnsureKey() error { +func (d *dkgSign) EnsureKey(ctx context.Context) error { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -92,7 +93,7 @@ func (d *dkgSign) EnsureKey() error { d.logger.Infof("Created DKGSign key with ID %s", key.ID()) - return d.safeAddKey(key) + return d.safeAddKey(ctx, key) } // Export implements DKGSign @@ -133,7 +134,7 @@ func (d *dkgSign) GetAll() (keys []dkgsignkey.Key, err error) { } // Import implements DKGSign -func (d *dkgSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, error) { +func (d *dkgSign) Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) { d.lock.Lock() defer d.lock.Unlock() if d.isLocked() { @@ -147,7 +148,7 @@ func (d *dkgSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, error if err == nil { return dkgsignkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, d.keyManager.safeAddKey(key) + return key, d.keyManager.safeAddKey(ctx, key) } // caller must hold lock diff --git a/core/services/keystore/dkgsign_test.go b/core/services/keystore/dkgsign_test.go index 5ea23a516be..8aa8cb1ad74 100644 --- a/core/services/keystore/dkgsign_test.go +++ b/core/services/keystore/dkgsign_test.go @@ -1,13 +1,14 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" @@ -15,18 +16,18 @@ import ( func Test_DKGSignKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.DKGSign() assert.NotNil(t, ks) reset := func() { + ctx := context.Background() // Executed on cleanup _, err := db.Exec("DELETE FROM encrypted_key_rings") require.NoError(t, err) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -44,7 +45,8 @@ func Test_DKGSignKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -53,15 +55,16 @@ func Test_DKGSignKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -71,14 +74,15 @@ func Test_DKGSignKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := dkgsignkey.New() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -89,13 +93,13 @@ func Test_DKGSignKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key/ensures it already exists", func(t *testing.T) { defer reset() - + ctx := testutils.Context(t) newKey, err := dkgsignkey.New() assert.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.NoError(t, err) - err = keyStore.DKGSign().EnsureKey() + err = keyStore.DKGSign().EnsureKey(ctx) assert.NoError(t, err) keys, err2 := ks.GetAll() assert.NoError(t, err2) @@ -107,12 +111,13 @@ func Test_DKGSignKeyStore_E2E(t *testing.T) { t.Run("auto creates a key if it doesn't exists when trying to ensure it already exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) keys, err := ks.GetAll() assert.NoError(t, err) assert.Equal(t, 0, len(keys)) - err = keyStore.DKGSign().EnsureKey() + err = keyStore.DKGSign().EnsureKey(ctx) assert.NoError(t, err) keys, err = ks.GetAll() diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index be59cb5e54c..a4365eb9092 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -13,8 +13,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -29,9 +29,9 @@ type Eth interface { Import(ctx context.Context, keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) Export(ctx context.Context, id string, password string) ([]byte, error) - Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error + Enable(ctx context.Context, address common.Address, chainID *big.Int) error + Disable(ctx context.Context, address common.Address, chainID *big.Int) error + Add(ctx context.Context, address common.Address, chainID *big.Int) error EnsureKeys(ctx context.Context, chainIDs ...*big.Int) error SubscribeToKeyChanges(ctx context.Context) (ch chan struct{}, unsub func()) @@ -55,18 +55,18 @@ type Eth interface { type eth struct { *keyManager keystateORM - q pg.Q + ds sqlutil.DataSource subscribers [](chan struct{}) subscribersMu *sync.RWMutex } var _ Eth = ð{} -func newEthKeyStore(km *keyManager, orm keystateORM, q pg.Q) *eth { +func newEthKeyStore(km *keyManager, orm keystateORM, ds sqlutil.DataSource) *eth { return ð{ keystateORM: orm, keyManager: km, - q: q, + ds: ds, subscribers: make([](chan struct{}), 0), subscribersMu: new(sync.RWMutex), } @@ -111,9 +111,10 @@ func (ks *eth) Create(ctx context.Context, chainIDs ...*big.Int) (ethkey.KeyV2, return ethkey.KeyV2{}, err } err = ks.add(ctx, key, chainIDs...) - if err == nil { - ks.notify() + if err != nil { + return ethkey.KeyV2{}, errors.Wrap(err, "unable to add eth key") } + ks.notify() ks.logger.Infow(fmt.Sprintf("Created EVM key with ID %s", key.Address.Hex()), "address", key.Address.Hex(), "evmChainIDs", chainIDs) return key, err } @@ -139,7 +140,7 @@ func (ks *eth) EnsureKeys(ctx context.Context, chainIDs ...*big.Int) (err error) } err = ks.add(ctx, newKey, chainID) if err != nil { - return err + return fmt.Errorf("failed to add key %s for chain %s: %w", newKey.Address, chainID, err) } ks.logger.Infow(fmt.Sprintf("Created EVM key with ID %s", newKey.Address.Hex()), "address", newKey.Address.Hex(), "evmChainID", chainID) } @@ -182,27 +183,29 @@ func (ks *eth) Export(ctx context.Context, id string, password string) ([]byte, return key.ToEncryptedJSON(password, ks.scryptParams) } -func (ks *eth) Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Add(ctx context.Context, address common.Address, chainID *big.Int) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return ErrKeyNotFound } - return ks.addKey(ctx, address, chainID, qopts...) + return ks.addKey(ctx, nil, address, chainID) } // caller must hold lock! -func (ks *eth) addKey(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +// ds is optional, for transactions +func (ks *eth) addKey(ctx context.Context, ds sqlutil.DataSource, address common.Address, chainID *big.Int) error { + if ds == nil { + ds = ks.ds + } state := new(ethkey.State) sql := `INSERT INTO evm.key_states (address, disabled, evm_chain_id, created_at, updated_at) VALUES ($1, false, $2, NOW(), NOW()) RETURNING *;` - q := ks.q.WithOpts(qopts...) - q = q.WithOpts(pg.WithParentCtx(ctx)) - if err := q.Get(state, sql, address, chainID.String()); err != nil { - return errors.Wrap(err, "failed to insert evm_key_state") + if err := ds.GetContext(ctx, state, sql, address, chainID.String()); err != nil { + return errors.Wrap(err, "failed to insert key_state") } // consider: do we really need a cache of the keystates? ks.keyStates.add(state) @@ -210,24 +213,23 @@ func (ks *eth) addKey(ctx context.Context, address common.Address, chainID *big. return nil } -func (ks *eth) Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Enable(ctx context.Context, address common.Address, chainID *big.Int) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return ErrKeyNotFound } - return ks.enable(ctx, address, chainID, qopts...) + return ks.enable(ctx, address, chainID) } // caller must hold lock! -func (ks *eth) enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) enable(ctx context.Context, address common.Address, chainID *big.Int) error { state := new(ethkey.State) - q := ks.q.WithOpts(qopts...) sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, false, NOW(), NOW()) ON CONFLICT ("address", "evm_chain_id") DO UPDATE SET "disabled" = false, "updated_at" = NOW() WHERE key_states."address" = $1 AND key_states."evm_chain_id" = $2 RETURNING *;` - if err := q.Get(state, sql, address, chainID.String()); err != nil { + if err := ks.ds.GetContext(ctx, state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") } @@ -240,23 +242,22 @@ func (ks *eth) enable(ctx context.Context, address common.Address, chainID *big. return nil } -func (ks *eth) Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Disable(ctx context.Context, address common.Address, chainID *big.Int) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return errors.Errorf("no key exists with ID %s", address.Hex()) } - return ks.disable(ctx, address, chainID, qopts...) + return ks.disable(ctx, address, chainID) } -func (ks *eth) disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) disable(ctx context.Context, address common.Address, chainID *big.Int) error { state := new(ethkey.State) - q := ks.q.WithOpts(qopts...) sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, true, NOW(), NOW()) ON CONFLICT ("address", "evm_chain_id") DO UPDATE SET "disabled" = true, "updated_at" = NOW() WHERE key_states."address" = $1 AND key_states."evm_chain_id" = $2 RETURNING *;` - if err := q.Get(state, sql, address, chainID.String()); err != nil { + if err := ks.ds.GetContext(ctx, state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to disable state") } @@ -279,8 +280,8 @@ func (ks *eth) Delete(ctx context.Context, id string) (ethkey.KeyV2, error) { if err != nil { return ethkey.KeyV2{}, err } - err = ks.safeRemoveKey(key, func(tx pg.Queryer) error { - _, err2 := tx.Exec(`DELETE FROM evm.key_states WHERE address = $1`, key.Address) + err = ks.safeRemoveKey(ctx, key, func(ds sqlutil.DataSource) error { + _, err2 := ds.ExecContext(ctx, `DELETE FROM evm.key_states WHERE address = $1`, key.Address) return err2 }) if err != nil { @@ -511,7 +512,7 @@ func (ks *eth) XXXTestingOnlySetState(ctx context.Context, state ethkey.State) { *existingState = state sql := `UPDATE evm.key_states SET address = :address, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() WHERE address = :address;` - _, err := ks.q.NamedExec(sql, state) + _, err := ks.ds.NamedExecContext(ctx, sql, state) if err != nil { panic(err.Error()) } @@ -565,9 +566,9 @@ func (ks *eth) keysForChain(chainID *big.Int, includeDisabled bool) (keys []ethk // caller must hold lock! func (ks *eth) add(ctx context.Context, key ethkey.KeyV2, chainIDs ...*big.Int) (err error) { - err = ks.safeAddKey(key, func(tx pg.Queryer) (serr error) { + err = ks.safeAddKey(ctx, key, func(tx sqlutil.DataSource) (serr error) { for _, chainID := range chainIDs { - if serr = ks.addKey(ctx, key.Address, chainID, pg.WithQueryer(tx)); serr != nil { + if serr = ks.addKey(ctx, tx, key.Address, chainID); serr != nil { return serr } } diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 6bc346bf4f8..07a41599f7d 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "fmt" "math/big" "sort" @@ -12,13 +13,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -27,18 +29,20 @@ import ( func Test_EthKeyStore(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) + db := sqlutil.WrapDataSource(pgtest.NewSqlxDB(t), logger.Test(t), sqlutil.TimeoutHook(func() time.Duration { + return 5 * time.Minute + }), sqlutil.MonitorHook(func() bool { return true })) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - err := keyStore.Unlock(cltest.Password) + keyStore := keystore.ExposedNewMaster(t, db) + err := keyStore.Unlock(testutils.Context(t), cltest.Password) require.NoError(t, err) ethKeyStore := keyStore.Eth() reset := func() { + ctx := context.Background() // Executed on cleanup keyStore.ResetXXXTestOnly() - require.NoError(t, commonutils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) - require.NoError(t, commonutils.JustError(db.Exec("DELETE FROM evm.key_states"))) - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, commonutils.JustError(db.ExecContext(ctx, "DELETE FROM encrypted_key_rings"))) + require.NoError(t, commonutils.JustError(db.ExecContext(ctx, "DELETE FROM evm.key_states"))) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } const statesTableName = "evm.key_states" @@ -58,11 +62,11 @@ func Test_EthKeyStore(t *testing.T) { cltest.AssertCount(t, db, statesTableName, 1) var state ethkey.State sql := fmt.Sprintf(`SELECT address, disabled, evm_chain_id, created_at, updated_at from %s LIMIT 1`, statesTableName) - require.NoError(t, db.Get(&state, sql)) + require.NoError(t, db.GetContext(ctx, &state, sql)) require.Equal(t, state.Address.Address(), retrievedKeys[0].Address) // adds key to db keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) retrievedKeys, err = ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 1, len(retrievedKeys)) @@ -217,9 +221,8 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() t.Run("should error when no addresses", func(t *testing.T) { @@ -341,8 +344,7 @@ func Test_EthKeyStore_SignTx(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - config := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) ethKeyStore := keyStore.Eth() k, _ := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -364,17 +366,17 @@ func Test_EthKeyStore_E2E(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - err := keyStore.Unlock(cltest.Password) + keyStore := keystore.ExposedNewMaster(t, db) + err := keyStore.Unlock(testutils.Context(t), cltest.Password) require.NoError(t, err) ks := keyStore.Eth() reset := func() { + ctx := testutils.Context(t) keyStore.ResetXXXTestOnly() require.NoError(t, commonutils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) require.NoError(t, commonutils.JustError(db.Exec("DELETE FROM evm.key_states"))) - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -499,8 +501,7 @@ func Test_EthKeyStore_SubscribeToKeyChanges(t *testing.T) { chDone := make(chan struct{}) defer func() { close(chDone) }() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() chSub, unsubscribe := ks.SubscribeToKeyChanges(ctx) defer unsubscribe() @@ -567,8 +568,7 @@ func Test_EthKeyStore_Enable(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() t.Run("already existing disabled key gets enabled", func(t *testing.T) { @@ -618,8 +618,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { t.Run("creates one unique key per chain if none exist", func(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() testutils.AssertCount(t, db, "evm.key_states", 0) @@ -634,8 +633,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { t.Run("does nothing if a key exists for a chain", func(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() // Add one enabled key @@ -658,8 +656,7 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { t.Run("does nothing if a key exists but is disabled for a chain", func(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() // Add one enabled key @@ -693,8 +690,7 @@ func Test_EthKeyStore_Delete(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() randKeyID := utils.RandomAddress().Hex() @@ -741,8 +737,7 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() // create keys @@ -827,8 +822,7 @@ func Test_EthKeyStore_Disable(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) ks := keyStore.Eth() t.Run("creates key, deletes it unsafely and then enable creates it again", func(t *testing.T) { diff --git a/core/services/keystore/helpers_test.go b/core/services/keystore/helpers_test.go index d0b2a21ab38..e53e0af0c20 100644 --- a/core/services/keystore/helpers_test.go +++ b/core/services/keystore/helpers_test.go @@ -1,15 +1,14 @@ package keystore import ( + "context" "testing" "github.com/stretchr/testify/require" - "github.com/jmoiron/sqlx" - + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -19,14 +18,14 @@ func mustNewEthKey(t *testing.T) *ethkey.KeyV2 { return &key } -func ExposedNewMaster(t *testing.T, db *sqlx.DB, cfg pg.QConfig) *master { - return newMaster(db, utils.FastScryptParams, logger.TestLogger(t), cfg) +func ExposedNewMaster(t *testing.T, ds sqlutil.DataSource) *master { + return newMaster(ds, utils.FastScryptParams, logger.TestLogger(t)) } -func (m *master) ExportedSave() error { +func (m *master) ExportedSave(ctx context.Context) error { m.lock.Lock() defer m.lock.Unlock() - return m.save() + return m.save(ctx) } func (m *master) ResetXXXTestOnly() { diff --git a/core/services/keystore/keystoretest.go b/core/services/keystore/keystoretest.go index 6efc8e76bcf..91dc87ffe95 100644 --- a/core/services/keystore/keystoretest.go +++ b/core/services/keystore/keystoretest.go @@ -1,13 +1,12 @@ package keystore import ( + "context" "errors" "sync" - "github.com/jmoiron/sqlx" - + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -19,25 +18,25 @@ import ( // to support DB callbacks. type memoryORM struct { keyRing *encryptedKeyRing - q pg.Queryer + ds sqlutil.DataSource mu sync.RWMutex } -func (o *memoryORM) isEmpty() (bool, error) { +func (o *memoryORM) isEmpty(ctx context.Context) (bool, error) { return false, nil } -func (o *memoryORM) saveEncryptedKeyRing(kr *encryptedKeyRing, callbacks ...func(pg.Queryer) error) (err error) { +func (o *memoryORM) saveEncryptedKeyRing(ctx context.Context, kr *encryptedKeyRing, callbacks ...func(sqlutil.DataSource) error) (err error) { o.mu.Lock() defer o.mu.Unlock() o.keyRing = kr for _, c := range callbacks { - err = errors.Join(err, c(o.q)) + err = errors.Join(err, c(o.ds)) } return } -func (o *memoryORM) getEncryptedKeyRing() (encryptedKeyRing, error) { +func (o *memoryORM) getEncryptedKeyRing(ctx context.Context) (encryptedKeyRing, error) { o.mu.RLock() defer o.mu.RUnlock() if o.keyRing == nil { @@ -46,15 +45,15 @@ func (o *memoryORM) getEncryptedKeyRing() (encryptedKeyRing, error) { return *o.keyRing, nil } -func newInMemoryORM(q pg.Queryer) *memoryORM { - return &memoryORM{q: q} +func newInMemoryORM(ds sqlutil.DataSource) *memoryORM { + return &memoryORM{ds: ds} } // NewInMemory sets up a keystore which NOOPs attempts to access the `encrypted_key_rings` table. Accessing `evm.key_states` // will still hit the DB. -func NewInMemory(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg pg.QConfig) *master { - dbORM := NewORM(db, lggr, cfg) - memoryORM := newInMemoryORM(dbORM.q) +func NewInMemory(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr logger.Logger) *master { + dbORM := NewORM(ds, lggr) + memoryORM := newInMemoryORM(ds) km := &keyManager{ orm: memoryORM, @@ -68,7 +67,7 @@ func NewInMemory(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logge keyManager: km, cosmos: newCosmosKeyStore(km), csa: newCSAKeyStore(km), - eth: newEthKeyStore(km, dbORM, dbORM.q), + eth: newEthKeyStore(km, dbORM, ds), ocr: newOCRKeyStore(km), ocr2: newOCR2KeyStore(km), p2p: newP2PKeyStore(km), diff --git a/core/services/keystore/master.go b/core/services/keystore/master.go index 05f19495f9d..bb5b21a96f0 100644 --- a/core/services/keystore/master.go +++ b/core/services/keystore/master.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "math/big" "reflect" @@ -8,8 +9,7 @@ import ( "github.com/pkg/errors" - "github.com/jmoiron/sqlx" - + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -22,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -50,8 +49,8 @@ type Master interface { Cosmos() Cosmos StarkNet() StarkNet VRF() VRF - Unlock(password string) error - IsEmpty() (bool, error) + Unlock(ctx context.Context, password string) error + IsEmpty(ctx context.Context) (bool, error) } type master struct { @@ -69,12 +68,12 @@ type master struct { dkgEncrypt *dkgEncrypt } -func New(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg pg.QConfig) Master { - return newMaster(db, scryptParams, lggr, cfg) +func New(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr logger.Logger) Master { + return newMaster(ds, scryptParams, lggr) } -func newMaster(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg pg.QConfig) *master { - orm := NewORM(db, lggr, cfg) +func newMaster(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr logger.Logger) *master { + orm := NewORM(ds, lggr) km := &keyManager{ orm: orm, keystateORM: orm, @@ -87,7 +86,7 @@ func newMaster(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, keyManager: km, cosmos: newCosmosKeyStore(km), csa: newCSAKeyStore(km), - eth: newEthKeyStore(km, orm, orm.q), + eth: newEthKeyStore(km, orm, orm.ds), ocr: newOCRKeyStore(km), ocr2: newOCR2KeyStore(km), p2p: newP2PKeyStore(km), @@ -144,13 +143,13 @@ func (ks *master) VRF() VRF { } type ORM interface { - isEmpty() (bool, error) - saveEncryptedKeyRing(*encryptedKeyRing, ...func(pg.Queryer) error) error - getEncryptedKeyRing() (encryptedKeyRing, error) + isEmpty(context.Context) (bool, error) + saveEncryptedKeyRing(context.Context, *encryptedKeyRing, ...func(sqlutil.DataSource) error) error + getEncryptedKeyRing(context.Context) (encryptedKeyRing, error) } type keystateORM interface { - loadKeyStates() (*keyStates, error) + loadKeyStates(context.Context) (*keyStates, error) } type keyManager struct { @@ -164,11 +163,11 @@ type keyManager struct { logger logger.Logger } -func (km *keyManager) IsEmpty() (bool, error) { - return km.orm.isEmpty() +func (km *keyManager) IsEmpty(ctx context.Context) (bool, error) { + return km.orm.isEmpty(ctx) } -func (km *keyManager) Unlock(password string) error { +func (km *keyManager) Unlock(ctx context.Context, password string) error { km.lock.Lock() defer km.lock.Unlock() // DEV: allow Unlock() to be idempotent - this is especially useful in tests, @@ -178,7 +177,7 @@ func (km *keyManager) Unlock(password string) error { } return nil } - ekr, err := km.orm.getEncryptedKeyRing() + ekr, err := km.orm.getEncryptedKeyRing(ctx) if err != nil { return errors.Wrap(err, "unable to get encrypted key ring") } @@ -189,7 +188,7 @@ func (km *keyManager) Unlock(password string) error { kr.logPubKeys(km.logger) km.keyRing = kr - ks, err := km.keystateORM.loadKeyStates() + ks, err := km.keystateORM.loadKeyStates(ctx) if err != nil { return errors.Wrap(err, "unable to load key states") } @@ -200,16 +199,16 @@ func (km *keyManager) Unlock(password string) error { } // caller must hold lock! -func (km *keyManager) save(callbacks ...func(pg.Queryer) error) error { +func (km *keyManager) save(ctx context.Context, callbacks ...func(sqlutil.DataSource) error) error { ekb, err := km.keyRing.Encrypt(km.password, km.scryptParams) if err != nil { return errors.Wrap(err, "unable to encrypt keyRing") } - return km.orm.saveEncryptedKeyRing(&ekb, callbacks...) + return km.orm.saveEncryptedKeyRing(ctx, &ekb, callbacks...) } // caller must hold lock! -func (km *keyManager) safeAddKey(unknownKey Key, callbacks ...func(pg.Queryer) error) error { +func (km *keyManager) safeAddKey(ctx context.Context, unknownKey Key, callbacks ...func(sqlutil.DataSource) error) error { fieldName, err := GetFieldNameForKey(unknownKey) if err != nil { return err @@ -221,7 +220,7 @@ func (km *keyManager) safeAddKey(unknownKey Key, callbacks ...func(pg.Queryer) e keyMap := keyRing.FieldByName(fieldName) keyMap.SetMapIndex(id, key) // save keyring to DB - err = km.save(callbacks...) + err = km.save(ctx, callbacks...) // if save fails, remove key from keyring if err != nil { keyMap.SetMapIndex(id, reflect.Value{}) @@ -231,7 +230,7 @@ func (km *keyManager) safeAddKey(unknownKey Key, callbacks ...func(pg.Queryer) e } // caller must hold lock! -func (km *keyManager) safeRemoveKey(unknownKey Key, callbacks ...func(pg.Queryer) error) (err error) { +func (km *keyManager) safeRemoveKey(ctx context.Context, unknownKey Key, callbacks ...func(sqlutil.DataSource) error) (err error) { fieldName, err := GetFieldNameForKey(unknownKey) if err != nil { return err @@ -242,7 +241,7 @@ func (km *keyManager) safeRemoveKey(unknownKey Key, callbacks ...func(pg.Queryer keyMap := keyRing.FieldByName(fieldName) keyMap.SetMapIndex(id, reflect.Value{}) // save keyring to DB - err = km.save(callbacks...) + err = km.save(ctx, callbacks...) // if save fails, add key back to keyRing if err != nil { keyMap.SetMapIndex(id, key) diff --git a/core/services/keystore/master_test.go b/core/services/keystore/master_test.go index 73f636c6625..e41a7a771ae 100644 --- a/core/services/keystore/master_test.go +++ b/core/services/keystore/master_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) @@ -16,9 +16,8 @@ func TestMasterKeystore_Unlock_Save(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) + keyStore := keystore.ExposedNewMaster(t, db) const tableName = "encrypted_key_rings" reset := func() { keyStore.ResetXXXTestOnly() @@ -28,36 +27,40 @@ func TestMasterKeystore_Unlock_Save(t *testing.T) { t.Run("can be unlocked more than once, as long as the passwords match", func(t *testing.T) { defer reset() - require.NoError(t, keyStore.Unlock(cltest.Password)) - require.NoError(t, keyStore.Unlock(cltest.Password)) - require.NoError(t, keyStore.Unlock(cltest.Password)) - require.Error(t, keyStore.Unlock("wrong password")) + ctx := testutils.Context(t) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) + require.Error(t, keyStore.Unlock(ctx, "wrong password")) }) t.Run("saves an empty keyRing", func(t *testing.T) { defer reset() - require.NoError(t, keyStore.Unlock(cltest.Password)) + ctx := testutils.Context(t) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) cltest.AssertCount(t, db, tableName, 1) - require.NoError(t, keyStore.ExportedSave()) + require.NoError(t, keyStore.ExportedSave(ctx)) cltest.AssertCount(t, db, tableName, 1) }) t.Run("won't load a saved keyRing if the password is incorrect", func(t *testing.T) { defer reset() - require.NoError(t, keyStore.Unlock(cltest.Password)) + ctx := testutils.Context(t) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) cltest.MustInsertRandomKey(t, keyStore.Eth()) // need at least 1 key to encrypt cltest.AssertCount(t, db, tableName, 1) keyStore.ResetXXXTestOnly() cltest.AssertCount(t, db, tableName, 1) - require.Error(t, keyStore.Unlock("password2")) + require.Error(t, keyStore.Unlock(ctx, "password2")) cltest.AssertCount(t, db, tableName, 1) }) t.Run("loads a saved keyRing if the password is correct", func(t *testing.T) { defer reset() - require.NoError(t, keyStore.Unlock(cltest.Password)) - require.NoError(t, keyStore.ExportedSave()) + ctx := testutils.Context(t) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) + require.NoError(t, keyStore.ExportedSave(ctx)) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) }) } diff --git a/core/services/keystore/mocks/cosmos.go b/core/services/keystore/mocks/cosmos.go index 40ba12d15d7..5e16a1a3c34 100644 --- a/core/services/keystore/mocks/cosmos.go +++ b/core/services/keystore/mocks/cosmos.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + cosmoskey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" mock "github.com/stretchr/testify/mock" @@ -13,17 +15,17 @@ type Cosmos struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *Cosmos) Add(key cosmoskey.Key) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *Cosmos) Add(ctx context.Context, key cosmoskey.Key) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(cosmoskey.Key) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, cosmoskey.Key) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -31,9 +33,9 @@ func (_m *Cosmos) Add(key cosmoskey.Key) error { return r0 } -// Create provides a mock function with given fields: -func (_m *Cosmos) Create() (cosmoskey.Key, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *Cosmos) Create(ctx context.Context) (cosmoskey.Key, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -41,17 +43,17 @@ func (_m *Cosmos) Create() (cosmoskey.Key, error) { var r0 cosmoskey.Key var r1 error - if rf, ok := ret.Get(0).(func() (cosmoskey.Key, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (cosmoskey.Key, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() cosmoskey.Key); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) cosmoskey.Key); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(cosmoskey.Key) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -59,9 +61,9 @@ func (_m *Cosmos) Create() (cosmoskey.Key, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *Cosmos) Delete(ctx context.Context, id string) (cosmoskey.Key, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -69,17 +71,17 @@ func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { var r0 cosmoskey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (cosmoskey.Key, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (cosmoskey.Key, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) cosmoskey.Key); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) cosmoskey.Key); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(cosmoskey.Key) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -87,17 +89,17 @@ func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *Cosmos) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *Cosmos) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -193,9 +195,9 @@ func (_m *Cosmos) GetAll() ([]cosmoskey.Key, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *Cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *Cosmos) Import(ctx context.Context, keyJSON []byte, password string) (cosmoskey.Key, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -203,17 +205,17 @@ func (_m *Cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) var r0 cosmoskey.Key var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (cosmoskey.Key, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (cosmoskey.Key, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) cosmoskey.Key); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) cosmoskey.Key); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(cosmoskey.Key) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/csa.go b/core/services/keystore/mocks/csa.go index ad5b25a27bd..c99fef9de8c 100644 --- a/core/services/keystore/mocks/csa.go +++ b/core/services/keystore/mocks/csa.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + csakey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" mock "github.com/stretchr/testify/mock" @@ -13,17 +15,17 @@ type CSA struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *CSA) Add(key csakey.KeyV2) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *CSA) Add(ctx context.Context, key csakey.KeyV2) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(csakey.KeyV2) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, csakey.KeyV2) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -31,9 +33,9 @@ func (_m *CSA) Add(key csakey.KeyV2) error { return r0 } -// Create provides a mock function with given fields: -func (_m *CSA) Create() (csakey.KeyV2, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *CSA) Create(ctx context.Context) (csakey.KeyV2, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -41,17 +43,17 @@ func (_m *CSA) Create() (csakey.KeyV2, error) { var r0 csakey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func() (csakey.KeyV2, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (csakey.KeyV2, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() csakey.KeyV2); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) csakey.KeyV2); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(csakey.KeyV2) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -59,9 +61,9 @@ func (_m *CSA) Create() (csakey.KeyV2, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *CSA) Delete(ctx context.Context, id string) (csakey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -69,17 +71,17 @@ func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { var r0 csakey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(string) (csakey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (csakey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) csakey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) csakey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(csakey.KeyV2) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -87,17 +89,17 @@ func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *CSA) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *CSA) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -193,9 +195,9 @@ func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *CSA) Import(ctx context.Context, keyJSON []byte, password string) (csakey.KeyV2, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -203,17 +205,17 @@ func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { var r0 csakey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (csakey.KeyV2, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (csakey.KeyV2, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) csakey.KeyV2); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) csakey.KeyV2); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(csakey.KeyV2) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/dkg_encrypt.go b/core/services/keystore/mocks/dkg_encrypt.go index e7e52bada25..48f50b3cec7 100644 --- a/core/services/keystore/mocks/dkg_encrypt.go +++ b/core/services/keystore/mocks/dkg_encrypt.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + dkgencryptkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" mock "github.com/stretchr/testify/mock" @@ -13,17 +15,17 @@ type DKGEncrypt struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *DKGEncrypt) Add(ctx context.Context, key dkgencryptkey.Key) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(dkgencryptkey.Key) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, dkgencryptkey.Key) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -31,9 +33,9 @@ func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { return r0 } -// Create provides a mock function with given fields: -func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *DKGEncrypt) Create(ctx context.Context) (dkgencryptkey.Key, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -41,17 +43,17 @@ func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { var r0 dkgencryptkey.Key var r1 error - if rf, ok := ret.Get(0).(func() (dkgencryptkey.Key, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (dkgencryptkey.Key, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() dkgencryptkey.Key); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) dkgencryptkey.Key); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(dkgencryptkey.Key) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -59,9 +61,9 @@ func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *DKGEncrypt) Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -69,17 +71,17 @@ func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { var r0 dkgencryptkey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (dkgencryptkey.Key, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) dkgencryptkey.Key); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) dkgencryptkey.Key); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(dkgencryptkey.Key) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -87,17 +89,17 @@ func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *DKGEncrypt) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *DKGEncrypt) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -193,9 +195,9 @@ func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *DKGEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *DKGEncrypt) Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -203,17 +205,17 @@ func (_m *DKGEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key var r0 dkgencryptkey.Key var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (dkgencryptkey.Key, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (dkgencryptkey.Key, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) dkgencryptkey.Key); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) dkgencryptkey.Key); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(dkgencryptkey.Key) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/dkg_sign.go b/core/services/keystore/mocks/dkg_sign.go index e5c6434d90d..fd16f573a87 100644 --- a/core/services/keystore/mocks/dkg_sign.go +++ b/core/services/keystore/mocks/dkg_sign.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + dkgsignkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" mock "github.com/stretchr/testify/mock" @@ -13,17 +15,17 @@ type DKGSign struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *DKGSign) Add(key dkgsignkey.Key) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *DKGSign) Add(ctx context.Context, key dkgsignkey.Key) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(dkgsignkey.Key) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, dkgsignkey.Key) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -31,9 +33,9 @@ func (_m *DKGSign) Add(key dkgsignkey.Key) error { return r0 } -// Create provides a mock function with given fields: -func (_m *DKGSign) Create() (dkgsignkey.Key, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *DKGSign) Create(ctx context.Context) (dkgsignkey.Key, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -41,17 +43,17 @@ func (_m *DKGSign) Create() (dkgsignkey.Key, error) { var r0 dkgsignkey.Key var r1 error - if rf, ok := ret.Get(0).(func() (dkgsignkey.Key, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (dkgsignkey.Key, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() dkgsignkey.Key); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) dkgsignkey.Key); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(dkgsignkey.Key) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -59,9 +61,9 @@ func (_m *DKGSign) Create() (dkgsignkey.Key, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *DKGSign) Delete(ctx context.Context, id string) (dkgsignkey.Key, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -69,17 +71,17 @@ func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { var r0 dkgsignkey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (dkgsignkey.Key, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) dkgsignkey.Key); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) dkgsignkey.Key); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(dkgsignkey.Key) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -87,17 +89,17 @@ func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *DKGSign) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *DKGSign) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -193,9 +195,9 @@ func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *DKGSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *DKGSign) Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -203,17 +205,17 @@ func (_m *DKGSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, erro var r0 dkgsignkey.Key var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (dkgsignkey.Key, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (dkgsignkey.Key, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) dkgsignkey.Key); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) dkgsignkey.Key); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(dkgsignkey.Key) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index a5dd612d9e5..f4a2bea1b02 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -12,8 +12,6 @@ import ( mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - types "github.com/ethereum/go-ethereum/core/types" ) @@ -22,24 +20,17 @@ type Eth struct { mock.Mock } -// Add provides a mock function with given fields: ctx, address, chainID, qopts -func (_m *Eth) Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// Add provides a mock function with given fields: ctx, address, chainID +func (_m *Eth) Add(ctx context.Context, address common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(ctx, address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) error); ok { + r0 = rf(ctx, address, chainID) } else { r0 = ret.Error(0) } @@ -128,24 +119,17 @@ func (_m *Eth) Delete(ctx context.Context, id string) (ethkey.KeyV2, error) { return r0, r1 } -// Disable provides a mock function with given fields: ctx, address, chainID, qopts -func (_m *Eth) Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// Disable provides a mock function with given fields: ctx, address, chainID +func (_m *Eth) Disable(ctx context.Context, address common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { panic("no return value specified for Disable") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(ctx, address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) error); ok { + r0 = rf(ctx, address, chainID) } else { r0 = ret.Error(0) } @@ -153,24 +137,17 @@ func (_m *Eth) Disable(ctx context.Context, address common.Address, chainID *big return r0 } -// Enable provides a mock function with given fields: ctx, address, chainID, qopts -func (_m *Eth) Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// Enable provides a mock function with given fields: ctx, address, chainID +func (_m *Eth) Enable(ctx context.Context, address common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { panic("no return value specified for Enable") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(ctx, address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) error); ok { + r0 = rf(ctx, address, chainID) } else { r0 = ret.Error(0) } diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index 3025f5b103a..2739c4bbe34 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + keystore "github.com/smartcontractkit/chainlink/v2/core/services/keystore" mock "github.com/stretchr/testify/mock" ) @@ -112,9 +114,9 @@ func (_m *Master) Eth() keystore.Eth { return r0 } -// IsEmpty provides a mock function with given fields: -func (_m *Master) IsEmpty() (bool, error) { - ret := _m.Called() +// IsEmpty provides a mock function with given fields: ctx +func (_m *Master) IsEmpty(ctx context.Context) (bool, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for IsEmpty") @@ -122,17 +124,17 @@ func (_m *Master) IsEmpty() (bool, error) { var r0 bool var r1 error - if rf, ok := ret.Get(0).(func() (bool, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -240,17 +242,17 @@ func (_m *Master) StarkNet() keystore.StarkNet { return r0 } -// Unlock provides a mock function with given fields: password -func (_m *Master) Unlock(password string) error { - ret := _m.Called(password) +// Unlock provides a mock function with given fields: ctx, password +func (_m *Master) Unlock(ctx context.Context, password string) error { + ret := _m.Called(ctx, password) if len(ret) == 0 { panic("no return value specified for Unlock") } var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(password) + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, password) } else { r0 = ret.Error(0) } diff --git a/core/services/keystore/mocks/ocr.go b/core/services/keystore/mocks/ocr.go index e1c4d588330..76659d0d4d1 100644 --- a/core/services/keystore/mocks/ocr.go +++ b/core/services/keystore/mocks/ocr.go @@ -1,10 +1,13 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( - ocrkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" + context "context" + mock "github.com/stretchr/testify/mock" + + ocrkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" ) // OCR is an autogenerated mock type for the OCR type @@ -12,17 +15,17 @@ type OCR struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *OCR) Add(key ocrkey.KeyV2) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *OCR) Add(ctx context.Context, key ocrkey.KeyV2) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(ocrkey.KeyV2) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, ocrkey.KeyV2) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -30,9 +33,9 @@ func (_m *OCR) Add(key ocrkey.KeyV2) error { return r0 } -// Create provides a mock function with given fields: -func (_m *OCR) Create() (ocrkey.KeyV2, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *OCR) Create(ctx context.Context) (ocrkey.KeyV2, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -40,17 +43,17 @@ func (_m *OCR) Create() (ocrkey.KeyV2, error) { var r0 ocrkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func() (ocrkey.KeyV2, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (ocrkey.KeyV2, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() ocrkey.KeyV2); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) ocrkey.KeyV2); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(ocrkey.KeyV2) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -58,9 +61,9 @@ func (_m *OCR) Create() (ocrkey.KeyV2, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *OCR) Delete(ctx context.Context, id string) (ocrkey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -68,17 +71,17 @@ func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { var r0 ocrkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(string) (ocrkey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (ocrkey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) ocrkey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) ocrkey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(ocrkey.KeyV2) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -86,17 +89,17 @@ func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *OCR) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *OCR) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -192,9 +195,9 @@ func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *OCR) Import(ctx context.Context, keyJSON []byte, password string) (ocrkey.KeyV2, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -202,17 +205,17 @@ func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { var r0 ocrkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (ocrkey.KeyV2, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (ocrkey.KeyV2, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) ocrkey.KeyV2); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) ocrkey.KeyV2); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(ocrkey.KeyV2) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/ocr2.go b/core/services/keystore/mocks/ocr2.go index d44e739deed..74c8eed70cc 100644 --- a/core/services/keystore/mocks/ocr2.go +++ b/core/services/keystore/mocks/ocr2.go @@ -1,8 +1,10 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + chaintype "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" mock "github.com/stretchr/testify/mock" @@ -15,17 +17,17 @@ type OCR2 struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *OCR2) Add(key ocr2key.KeyBundle) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *OCR2) Add(ctx context.Context, key ocr2key.KeyBundle) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(ocr2key.KeyBundle) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, ocr2key.KeyBundle) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -33,9 +35,9 @@ func (_m *OCR2) Add(key ocr2key.KeyBundle) error { return r0 } -// Create provides a mock function with given fields: _a0 -func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { - ret := _m.Called(_a0) +// Create provides a mock function with given fields: _a0, _a1 +func (_m *OCR2) Create(_a0 context.Context, _a1 chaintype.ChainType) (ocr2key.KeyBundle, error) { + ret := _m.Called(_a0, _a1) if len(ret) == 0 { panic("no return value specified for Create") @@ -43,19 +45,19 @@ func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { var r0 ocr2key.KeyBundle var r1 error - if rf, ok := ret.Get(0).(func(chaintype.ChainType) (ocr2key.KeyBundle, error)); ok { - return rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, chaintype.ChainType) (ocr2key.KeyBundle, error)); ok { + return rf(_a0, _a1) } - if rf, ok := ret.Get(0).(func(chaintype.ChainType) ocr2key.KeyBundle); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, chaintype.ChainType) ocr2key.KeyBundle); ok { + r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(ocr2key.KeyBundle) } } - if rf, ok := ret.Get(1).(func(chaintype.ChainType) error); ok { - r1 = rf(_a0) + if rf, ok := ret.Get(1).(func(context.Context, chaintype.ChainType) error); ok { + r1 = rf(_a0, _a1) } else { r1 = ret.Error(1) } @@ -63,17 +65,17 @@ func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *OCR2) Delete(id string) error { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *OCR2) Delete(ctx context.Context, id string) error { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") } var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, id) } else { r0 = ret.Error(0) } @@ -81,13 +83,14 @@ func (_m *OCR2) Delete(id string) error { return r0 } -// EnsureKeys provides a mock function with given fields: enabledChains -func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { +// EnsureKeys provides a mock function with given fields: ctx, enabledChains +func (_m *OCR2) EnsureKeys(ctx context.Context, enabledChains ...chaintype.ChainType) error { _va := make([]interface{}, len(enabledChains)) for _i := range enabledChains { _va[_i] = enabledChains[_i] } var _ca []interface{} + _ca = append(_ca, ctx) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -96,8 +99,8 @@ func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { } var r0 error - if rf, ok := ret.Get(0).(func(...chaintype.ChainType) error); ok { - r0 = rf(enabledChains...) + if rf, ok := ret.Get(0).(func(context.Context, ...chaintype.ChainType) error); ok { + r0 = rf(ctx, enabledChains...) } else { r0 = ret.Error(0) } @@ -225,9 +228,9 @@ func (_m *OCR2) GetAllOfType(_a0 chaintype.ChainType) ([]ocr2key.KeyBundle, erro return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *OCR2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *OCR2) Import(ctx context.Context, keyJSON []byte, password string) (ocr2key.KeyBundle, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -235,19 +238,19 @@ func (_m *OCR2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, erro var r0 ocr2key.KeyBundle var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (ocr2key.KeyBundle, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (ocr2key.KeyBundle, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) ocr2key.KeyBundle); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) ocr2key.KeyBundle); ok { + r0 = rf(ctx, keyJSON, password) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(ocr2key.KeyBundle) } } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/p2p.go b/core/services/keystore/mocks/p2p.go index fa2a1b6ceeb..cb5a9329e54 100644 --- a/core/services/keystore/mocks/p2p.go +++ b/core/services/keystore/mocks/p2p.go @@ -1,10 +1,13 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( - p2pkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + context "context" + mock "github.com/stretchr/testify/mock" + + p2pkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) // P2P is an autogenerated mock type for the P2P type @@ -12,17 +15,17 @@ type P2P struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *P2P) Add(key p2pkey.KeyV2) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *P2P) Add(ctx context.Context, key p2pkey.KeyV2) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(p2pkey.KeyV2) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, p2pkey.KeyV2) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -30,9 +33,9 @@ func (_m *P2P) Add(key p2pkey.KeyV2) error { return r0 } -// Create provides a mock function with given fields: -func (_m *P2P) Create() (p2pkey.KeyV2, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *P2P) Create(ctx context.Context) (p2pkey.KeyV2, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -40,17 +43,17 @@ func (_m *P2P) Create() (p2pkey.KeyV2, error) { var r0 p2pkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func() (p2pkey.KeyV2, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (p2pkey.KeyV2, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() p2pkey.KeyV2); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) p2pkey.KeyV2); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(p2pkey.KeyV2) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -58,9 +61,9 @@ func (_m *P2P) Create() (p2pkey.KeyV2, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *P2P) Delete(ctx context.Context, id p2pkey.PeerID) (p2pkey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -68,17 +71,17 @@ func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { var r0 p2pkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(p2pkey.PeerID) p2pkey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, p2pkey.PeerID) p2pkey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(p2pkey.KeyV2) } - if rf, ok := ret.Get(1).(func(p2pkey.PeerID) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, p2pkey.PeerID) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -86,17 +89,17 @@ func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *P2P) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *P2P) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -220,9 +223,9 @@ func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *P2P) Import(ctx context.Context, keyJSON []byte, password string) (p2pkey.KeyV2, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -230,17 +233,17 @@ func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { var r0 p2pkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (p2pkey.KeyV2, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (p2pkey.KeyV2, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) p2pkey.KeyV2); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) p2pkey.KeyV2); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(p2pkey.KeyV2) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/solana.go b/core/services/keystore/mocks/solana.go index c2cc4139bab..2f9514cc1da 100644 --- a/core/services/keystore/mocks/solana.go +++ b/core/services/keystore/mocks/solana.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -15,17 +15,17 @@ type Solana struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *Solana) Add(key solkey.Key) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *Solana) Add(ctx context.Context, key solkey.Key) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(solkey.Key) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, solkey.Key) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -33,9 +33,9 @@ func (_m *Solana) Add(key solkey.Key) error { return r0 } -// Create provides a mock function with given fields: -func (_m *Solana) Create() (solkey.Key, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *Solana) Create(ctx context.Context) (solkey.Key, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -43,17 +43,17 @@ func (_m *Solana) Create() (solkey.Key, error) { var r0 solkey.Key var r1 error - if rf, ok := ret.Get(0).(func() (solkey.Key, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (solkey.Key, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() solkey.Key); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) solkey.Key); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(solkey.Key) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -61,9 +61,9 @@ func (_m *Solana) Create() (solkey.Key, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *Solana) Delete(id string) (solkey.Key, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *Solana) Delete(ctx context.Context, id string) (solkey.Key, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -71,17 +71,17 @@ func (_m *Solana) Delete(id string) (solkey.Key, error) { var r0 solkey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (solkey.Key, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (solkey.Key, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) solkey.Key); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) solkey.Key); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(solkey.Key) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -89,17 +89,17 @@ func (_m *Solana) Delete(id string) (solkey.Key, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *Solana) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *Solana) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -195,9 +195,9 @@ func (_m *Solana) GetAll() ([]solkey.Key, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *Solana) Import(ctx context.Context, keyJSON []byte, password string) (solkey.Key, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -205,17 +205,17 @@ func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { var r0 solkey.Key var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (solkey.Key, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (solkey.Key, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) solkey.Key); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) solkey.Key); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(solkey.Key) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/starknet.go b/core/services/keystore/mocks/starknet.go index c3d74a8389f..a6cc0d5e5f3 100644 --- a/core/services/keystore/mocks/starknet.go +++ b/core/services/keystore/mocks/starknet.go @@ -1,10 +1,13 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( - starkkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" + context "context" + mock "github.com/stretchr/testify/mock" + + starkkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" ) // StarkNet is an autogenerated mock type for the StarkNet type @@ -12,17 +15,17 @@ type StarkNet struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *StarkNet) Add(key starkkey.Key) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *StarkNet) Add(ctx context.Context, key starkkey.Key) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(starkkey.Key) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, starkkey.Key) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -30,9 +33,9 @@ func (_m *StarkNet) Add(key starkkey.Key) error { return r0 } -// Create provides a mock function with given fields: -func (_m *StarkNet) Create() (starkkey.Key, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *StarkNet) Create(ctx context.Context) (starkkey.Key, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -40,17 +43,17 @@ func (_m *StarkNet) Create() (starkkey.Key, error) { var r0 starkkey.Key var r1 error - if rf, ok := ret.Get(0).(func() (starkkey.Key, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (starkkey.Key, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() starkkey.Key); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) starkkey.Key); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(starkkey.Key) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -58,9 +61,9 @@ func (_m *StarkNet) Create() (starkkey.Key, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *StarkNet) Delete(ctx context.Context, id string) (starkkey.Key, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -68,17 +71,17 @@ func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { var r0 starkkey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (starkkey.Key, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (starkkey.Key, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) starkkey.Key); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) starkkey.Key); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(starkkey.Key) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -86,17 +89,17 @@ func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { return r0, r1 } -// EnsureKey provides a mock function with given fields: -func (_m *StarkNet) EnsureKey() error { - ret := _m.Called() +// EnsureKey provides a mock function with given fields: ctx +func (_m *StarkNet) EnsureKey(ctx context.Context) error { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for EnsureKey") } var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) } else { r0 = ret.Error(0) } @@ -192,9 +195,9 @@ func (_m *StarkNet) GetAll() ([]starkkey.Key, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *StarkNet) Import(keyJSON []byte, password string) (starkkey.Key, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *StarkNet) Import(ctx context.Context, keyJSON []byte, password string) (starkkey.Key, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -202,17 +205,17 @@ func (_m *StarkNet) Import(keyJSON []byte, password string) (starkkey.Key, error var r0 starkkey.Key var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (starkkey.Key, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (starkkey.Key, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) starkkey.Key); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) starkkey.Key); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(starkkey.Key) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/mocks/vrf.go b/core/services/keystore/mocks/vrf.go index ab730ebec67..87c6a724bdb 100644 --- a/core/services/keystore/mocks/vrf.go +++ b/core/services/keystore/mocks/vrf.go @@ -1,8 +1,9 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" big "math/big" mock "github.com/stretchr/testify/mock" @@ -15,17 +16,17 @@ type VRF struct { mock.Mock } -// Add provides a mock function with given fields: key -func (_m *VRF) Add(key vrfkey.KeyV2) error { - ret := _m.Called(key) +// Add provides a mock function with given fields: ctx, key +func (_m *VRF) Add(ctx context.Context, key vrfkey.KeyV2) error { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Add") } var r0 error - if rf, ok := ret.Get(0).(func(vrfkey.KeyV2) error); ok { - r0 = rf(key) + if rf, ok := ret.Get(0).(func(context.Context, vrfkey.KeyV2) error); ok { + r0 = rf(ctx, key) } else { r0 = ret.Error(0) } @@ -33,9 +34,9 @@ func (_m *VRF) Add(key vrfkey.KeyV2) error { return r0 } -// Create provides a mock function with given fields: -func (_m *VRF) Create() (vrfkey.KeyV2, error) { - ret := _m.Called() +// Create provides a mock function with given fields: ctx +func (_m *VRF) Create(ctx context.Context) (vrfkey.KeyV2, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") @@ -43,17 +44,17 @@ func (_m *VRF) Create() (vrfkey.KeyV2, error) { var r0 vrfkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func() (vrfkey.KeyV2, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (vrfkey.KeyV2, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() vrfkey.KeyV2); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) vrfkey.KeyV2); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(vrfkey.KeyV2) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -61,9 +62,9 @@ func (_m *VRF) Create() (vrfkey.KeyV2, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *VRF) Delete(ctx context.Context, id string) (vrfkey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -71,17 +72,17 @@ func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { var r0 vrfkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(string) (vrfkey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (vrfkey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) vrfkey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) vrfkey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(vrfkey.KeyV2) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -205,9 +206,9 @@ func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password -func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { - ret := _m.Called(keyJSON, password) +// Import provides a mock function with given fields: ctx, keyJSON, password +func (_m *VRF) Import(ctx context.Context, keyJSON []byte, password string) (vrfkey.KeyV2, error) { + ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") @@ -215,17 +216,17 @@ func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { var r0 vrfkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func([]byte, string) (vrfkey.KeyV2, error)); ok { - return rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (vrfkey.KeyV2, error)); ok { + return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func([]byte, string) vrfkey.KeyV2); ok { - r0 = rf(keyJSON, password) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) vrfkey.KeyV2); ok { + r0 = rf(ctx, keyJSON, password) } else { r0 = ret.Get(0).(vrfkey.KeyV2) } - if rf, ok := ret.Get(1).(func([]byte, string) error); ok { - r1 = rf(keyJSON, password) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { + r1 = rf(ctx, keyJSON, password) } else { r1 = ret.Error(1) } diff --git a/core/services/keystore/ocr.go b/core/services/keystore/ocr.go index dda5bfa13c3..7cacbbfff97 100644 --- a/core/services/keystore/ocr.go +++ b/core/services/keystore/ocr.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" @@ -13,12 +14,12 @@ import ( type OCR interface { Get(id string) (ocrkey.KeyV2, error) GetAll() ([]ocrkey.KeyV2, error) - Create() (ocrkey.KeyV2, error) - Add(key ocrkey.KeyV2) error - Delete(id string) (ocrkey.KeyV2, error) - Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) + Create(ctx context.Context) (ocrkey.KeyV2, error) + Add(ctx context.Context, key ocrkey.KeyV2) error + Delete(ctx context.Context, id string) (ocrkey.KeyV2, error) + Import(ctx context.Context, keyJSON []byte, password string) (ocrkey.KeyV2, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } // KeyNotFoundError is returned when we don't find a requested key @@ -64,7 +65,7 @@ func (ks *ocr) GetAll() (keys []ocrkey.KeyV2, _ error) { return keys, nil } -func (ks *ocr) Create() (ocrkey.KeyV2, error) { +func (ks *ocr) Create(ctx context.Context) (ocrkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -74,10 +75,10 @@ func (ks *ocr) Create() (ocrkey.KeyV2, error) { if err != nil { return ocrkey.KeyV2{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *ocr) Add(key ocrkey.KeyV2) error { +func (ks *ocr) Add(ctx context.Context, key ocrkey.KeyV2) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -86,10 +87,10 @@ func (ks *ocr) Add(key ocrkey.KeyV2) error { if _, found := ks.keyRing.OCR[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *ocr) Delete(id string) (ocrkey.KeyV2, error) { +func (ks *ocr) Delete(ctx context.Context, id string) (ocrkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -99,11 +100,11 @@ func (ks *ocr) Delete(id string) (ocrkey.KeyV2, error) { if err != nil { return ocrkey.KeyV2{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *ocr) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { +func (ks *ocr) Import(ctx context.Context, keyJSON []byte, password string) (ocrkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -116,7 +117,7 @@ func (ks *ocr) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { if _, found := ks.keyRing.OCR[key.ID()]; found { return ocrkey.KeyV2{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *ocr) Export(id string, password string) ([]byte, error) { @@ -133,7 +134,7 @@ func (ks *ocr) Export(id string, password string) ([]byte, error) { } // EnsureKey verifies whether the OCR key has been seeded, if not, it creates it. -func (ks *ocr) EnsureKey() error { +func (ks *ocr) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -151,7 +152,7 @@ func (ks *ocr) EnsureKey() error { ks.logger.Infof("Created OCR key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } func (ks *ocr) getByID(id string) (ocrkey.KeyV2, error) { diff --git a/core/services/keystore/ocr2.go b/core/services/keystore/ocr2.go index a6460bf1ae5..4edbe2ba741 100644 --- a/core/services/keystore/ocr2.go +++ b/core/services/keystore/ocr2.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" @@ -15,12 +16,12 @@ type OCR2 interface { Get(id string) (ocr2key.KeyBundle, error) GetAll() ([]ocr2key.KeyBundle, error) GetAllOfType(chaintype.ChainType) ([]ocr2key.KeyBundle, error) - Create(chaintype.ChainType) (ocr2key.KeyBundle, error) - Add(key ocr2key.KeyBundle) error - Delete(id string) error - Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error) + Create(context.Context, chaintype.ChainType) (ocr2key.KeyBundle, error) + Add(ctx context.Context, key ocr2key.KeyBundle) error + Delete(ctx context.Context, id string) error + Import(ctx context.Context, keyJSON []byte, password string) (ocr2key.KeyBundle, error) Export(id string, password string) ([]byte, error) - EnsureKeys(enabledChains ...chaintype.ChainType) error + EnsureKeys(ctx context.Context, enabledChains ...chaintype.ChainType) error } type ocr2 struct { @@ -67,16 +68,16 @@ func (ks ocr2) GetAllOfType(chainType chaintype.ChainType) ([]ocr2key.KeyBundle, return ks.getAllOfType(chainType) } -func (ks ocr2) Create(chainType chaintype.ChainType) (ocr2key.KeyBundle, error) { +func (ks ocr2) Create(ctx context.Context, chainType chaintype.ChainType) (ocr2key.KeyBundle, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { return nil, ErrLocked } - return ks.create(chainType) + return ks.create(ctx, chainType) } -func (ks ocr2) Add(key ocr2key.KeyBundle) error { +func (ks ocr2) Add(ctx context.Context, key ocr2key.KeyBundle) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -85,10 +86,10 @@ func (ks ocr2) Add(key ocr2key.KeyBundle) error { if _, found := ks.keyRing.OCR2[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks ocr2) Delete(id string) error { +func (ks ocr2) Delete(ctx context.Context, id string) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -98,11 +99,11 @@ func (ks ocr2) Delete(id string) error { if err != nil { return err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return err } -func (ks ocr2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error) { +func (ks ocr2) Import(ctx context.Context, keyJSON []byte, password string) (ocr2key.KeyBundle, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -115,7 +116,7 @@ func (ks ocr2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error if _, found := ks.keyRing.OCR[key.ID()]; found { return nil, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks ocr2) Export(id string, password string) ([]byte, error) { @@ -131,7 +132,7 @@ func (ks ocr2) Export(id string, password string) ([]byte, error) { return ocr2key.ToEncryptedJSON(key, password, ks.scryptParams) } -func (ks ocr2) EnsureKeys(enabledChains ...chaintype.ChainType) error { +func (ks ocr2) EnsureKeys(ctx context.Context, enabledChains ...chaintype.ChainType) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -148,7 +149,7 @@ func (ks ocr2) EnsureKeys(enabledChains ...chaintype.ChainType) error { continue } - created, err := ks.create(chainType) + created, err := ks.create(ctx, chainType) if err != nil { return err } @@ -177,7 +178,7 @@ func (ks ocr2) getAllOfType(chainType chaintype.ChainType) ([]ocr2key.KeyBundle, return keys, nil } -func (ks ocr2) create(chainType chaintype.ChainType) (ocr2key.KeyBundle, error) { +func (ks ocr2) create(ctx context.Context, chainType chaintype.ChainType) (ocr2key.KeyBundle, error) { if !chaintype.IsSupportedChainType(chainType) { return nil, chaintype.NewErrInvalidChainType(chainType) } @@ -185,5 +186,5 @@ func (ks ocr2) create(chainType chaintype.ChainType) (ocr2key.KeyBundle, error) if err != nil { return nil, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } diff --git a/core/services/keystore/ocr2_test.go b/core/services/keystore/ocr2_test.go index 9223538a766..f2c8715ab4f 100644 --- a/core/services/keystore/ocr2_test.go +++ b/core/services/keystore/ocr2_test.go @@ -1,13 +1,14 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -16,15 +17,15 @@ import ( func Test_OCR2KeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.OCR2() reset := func() { + ctx := context.Background() // Executed on cleanup _, err := db.Exec("DELETE FROM encrypted_key_rings") require.NoError(t, err) keyStore.ResetXXXTestOnly() - err = keyStore.Unlock(cltest.Password) + err = keyStore.Unlock(ctx, cltest.Password) require.NoError(t, err) } @@ -43,9 +44,10 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("creates a key with valid type", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) // lopp through different chain types for _, chain := range chaintype.SupportedChainTypes { - key, err := ks.Create(chain) + key, err := ks.Create(ctx, chain) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -55,6 +57,7 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("gets keys by type", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) created := map[chaintype.ChainType]bool{} for _, chain := range chaintype.SupportedChainTypes { @@ -64,7 +67,7 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { require.NoError(t, err) require.Len(t, keys, 0) - _, err = ks.Create(chain) + _, err = ks.Create(ctx, chain) require.NoError(t, err) created[chain] = true @@ -83,26 +86,28 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("errors when creating a key with an invalid type", func(t *testing.T) { defer reset() - _, err := ks.Create("foobar") + ctx := testutils.Context(t) + _, err := ks.Create(ctx, "foobar") require.Error(t, err) }) t.Run("imports and exports a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) for _, chain := range chaintype.SupportedChainTypes { - key, err := ks.Create(chain) + key, err := ks.Create(ctx, chain) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) _, err = ks.Export("non-existent", cltest.Password) assert.Error(t, err) - err = ks.Delete(key.ID()) + err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) - _, err = ks.Import([]byte(""), cltest.Password) + _, err = ks.Import(ctx, []byte(""), cltest.Password) assert.Error(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -114,19 +119,20 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) for _, chain := range chaintype.SupportedChainTypes { newKey, err := ocr2key.New(chain) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - err = ks.Delete(newKey.ID()) + err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) - err = ks.Delete(newKey.ID()) + err = ks.Delete(ctx, newKey.ID()) assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -138,14 +144,15 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKeys(chaintype.SupportedChainTypes...) + ctx := testutils.Context(t) + err := ks.EnsureKeys(ctx, chaintype.SupportedChainTypes...) assert.NoError(t, err) keys, err := ks.GetAll() assert.NoError(t, err) require.Equal(t, len(chaintype.SupportedChainTypes), len(keys)) - err = ks.EnsureKeys(chaintype.SupportedChainTypes...) + err = ks.EnsureKeys(ctx, chaintype.SupportedChainTypes...) assert.NoError(t, err) // loop through different supported chain types @@ -158,7 +165,8 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { t.Run("ensures key only for enabled chains", func(t *testing.T) { defer reset() - err := ks.EnsureKeys(chaintype.EVM) + ctx := testutils.Context(t) + err := ks.EnsureKeys(ctx, chaintype.EVM) assert.NoError(t, err) keys, err := ks.GetAll() @@ -166,7 +174,7 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { require.Equal(t, 1, len(keys)) require.Equal(t, keys[0].ChainType(), chaintype.EVM) - err = ks.EnsureKeys(chaintype.Cosmos) + err = ks.EnsureKeys(ctx, chaintype.Cosmos) assert.NoError(t, err) keys, err = ks.GetAll() @@ -178,7 +186,7 @@ func Test_OCR2KeyStore_E2E(t *testing.T) { require.Equal(t, 1, len(cosmosKeys)) require.Equal(t, cosmosKeys[0].ChainType(), chaintype.Cosmos) - err = ks.EnsureKeys(chaintype.StarkNet) + err = ks.EnsureKeys(ctx, chaintype.StarkNet) assert.NoError(t, err) keys, err = ks.GetAll() diff --git a/core/services/keystore/ocr_test.go b/core/services/keystore/ocr_test.go index c65d576c452..b7a7b127f21 100644 --- a/core/services/keystore/ocr_test.go +++ b/core/services/keystore/ocr_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -8,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -16,14 +17,14 @@ import ( func Test_OCRKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.OCR() reset := func() { + ctx := context.Background() // Executed on cleaup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -41,7 +42,8 @@ func Test_OCRKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -50,21 +52,22 @@ func Test_OCRKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) _, err = ks.Export("non-existent", cltest.Password) assert.Error(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) - _, err = ks.Import([]byte(""), cltest.Password) + _, err = ks.Import(ctx, []byte(""), cltest.Password) assert.Error(t, err) - _, err = ks.Import(exportJSON, cltest.Password) + _, err = ks.Import(ctx, exportJSON, cltest.Password) assert.Error(t, err) assert.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -74,18 +77,19 @@ func Test_OCRKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := ocrkey.NewV2() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) assert.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -96,9 +100,10 @@ func Test_OCRKeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKey() + ctx := testutils.Context(t) + err := ks.EnsureKey(ctx) require.NoError(t, err) - err = ks.EnsureKey() + err = ks.EnsureKey(ctx) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) @@ -106,8 +111,9 @@ func Test_OCRKeyStore_E2E(t *testing.T) { }) t.Run("imports a key exported from a v1 keystore", func(t *testing.T) { + ctx := testutils.Context(t) exportedKey := `{"id":"7cfd89bbb018e4778a44fd61172e8834dd24b4a2baf61ead795143b117221c61","onChainSigningAddress":"ocrsad_0x2ed5b18b62dacd7a85b6ed19247ea718bdae6114","offChainPublicKey":"ocroff_62a76d04e13dae5870071badea6b113a5123f4ac1a2cbae6b2fb7070dd9dbf2d","configPublicKey":"ocrcfg_75581baab36744671c2b1d75071b07b08b9cb631b3a7155d2f590744983d9c41","crypto":{"cipher":"aes-128-ctr","ciphertext":"60d2e679f08e0b1538cf609e25f2d32c0b7d408f24cab22dd05bffd3b5580c65552097e203f6546e2d792a4f6adb69449fee0fe4dd7f1060970907518e7c33331abd076388af842f03d05c193b03f22f6bf0423d4ae99dbb563c7158b4eac2a31b03c90fb9fd7be217804243151c36c33504469632bc2c89be33e7b9157edf172a52af4d49fa125b8d0358ea63ace90bc181a7164b548e0f12288ec08b919b46afad1b36dbaeda32d8d657a43908f802b6f2354473f538437ba3bd0b0d374d8e836e623484b655c95f4ef11e30baaa47b9075c6dbb53147c4b489f45a4bdcfa6b56ef2e6eaa9e9b88b570517c991de359d7f07226c00259810a8a4196b7d5331e4126529eac9bd80b47b5540940f89ad0e728b3dd50e6da316d9f3cf9b3be9b87ca6b7868daa7e4142fc4a65fc77deea6f4f2b4bce1e38337aa827160d8c50cad92d157309aa251180b894ab1ca9923d709d","cipherparams":{"iv":"a9507e6f2b073c1da1082d40a24864d1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"267f9450f52af42a918ab5747043c88bd2035fa3d3e0f0cfd2b621981bc9320f"},"mac":"15aeb3fc1903f514bfe70cb2eb5a23820ba904f5edf8aeb1913d447797f74442"}}` - importedKey, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_") + importedKey, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_") require.NoError(t, err) require.Equal(t, "7cfd89bbb018e4778a44fd61172e8834dd24b4a2baf61ead795143b117221c61", importedKey.ID()) }) diff --git a/core/services/keystore/orm.go b/core/services/keystore/orm.go index 3d75d6f2369..d1c06f0b6a8 100644 --- a/core/services/keystore/orm.go +++ b/core/services/keystore/orm.go @@ -1,41 +1,41 @@ package keystore import ( + "context" "database/sql" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - - "github.com/jmoiron/sqlx" - "github.com/pkg/errors" ) -func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) ksORM { +func NewORM(ds sqlutil.DataSource, lggr logger.Logger) ksORM { namedLogger := lggr.Named("KeystoreORM") return ksORM{ - q: pg.NewQ(db, namedLogger, cfg), + ds: ds, lggr: namedLogger, } } type ksORM struct { - q pg.Q + ds sqlutil.DataSource lggr logger.Logger } -func (orm ksORM) isEmpty() (bool, error) { +func (orm ksORM) isEmpty(ctx context.Context) (bool, error) { var count int64 - err := orm.q.QueryRow("SELECT count(*) FROM encrypted_key_rings").Scan(&count) + err := orm.ds.QueryRowxContext(ctx, "SELECT count(*) FROM encrypted_key_rings").Scan(&count) if err != nil { return false, err } return count == 0, nil } -func (orm ksORM) saveEncryptedKeyRing(kr *encryptedKeyRing, callbacks ...func(pg.Queryer) error) error { - return orm.q.Transaction(func(tx pg.Queryer) error { - _, err := tx.Exec(` +func (orm ksORM) saveEncryptedKeyRing(ctx context.Context, kr *encryptedKeyRing, callbacks ...func(sqlutil.DataSource) error) error { + return sqlutil.TransactDataSource(ctx, orm.ds, nil, func(tx sqlutil.DataSource) error { + _, err := tx.ExecContext(ctx, ` UPDATE encrypted_key_rings SET encrypted_keys = $1 `, kr.EncryptedKeys) @@ -52,11 +52,11 @@ func (orm ksORM) saveEncryptedKeyRing(kr *encryptedKeyRing, callbacks ...func(pg }) } -func (orm ksORM) getEncryptedKeyRing() (kr encryptedKeyRing, err error) { - err = orm.q.Get(&kr, `SELECT * FROM encrypted_key_rings LIMIT 1`) +func (orm ksORM) getEncryptedKeyRing(ctx context.Context) (kr encryptedKeyRing, err error) { + err = orm.ds.GetContext(ctx, &kr, `SELECT * FROM encrypted_key_rings LIMIT 1`) if errors.Is(err, sql.ErrNoRows) { sql := `INSERT INTO encrypted_key_rings (encrypted_keys, updated_at) VALUES (NULL, NOW()) RETURNING *;` - err2 := orm.q.Get(&kr, sql) + err2 := orm.ds.GetContext(ctx, &kr, sql) if err2 != nil { return kr, err2 @@ -67,10 +67,10 @@ func (orm ksORM) getEncryptedKeyRing() (kr encryptedKeyRing, err error) { return kr, nil } -func (orm ksORM) loadKeyStates() (*keyStates, error) { +func (orm ksORM) loadKeyStates(ctx context.Context) (*keyStates, error) { ks := newKeyStates() var ethkeystates []*ethkey.State - if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, disabled, created_at, updated_at FROM evm.key_states`); err != nil { + if err := orm.ds.SelectContext(ctx, ðkeystates, `SELECT id, address, evm_chain_id, disabled, created_at, updated_at FROM evm.key_states`); err != nil { return ks, errors.Wrap(err, "error loading evm.key_states from DB") } for _, state := range ethkeystates { diff --git a/core/services/keystore/p2p.go b/core/services/keystore/p2p.go index ee2c64c021d..ee5bc647b5d 100644 --- a/core/services/keystore/p2p.go +++ b/core/services/keystore/p2p.go @@ -1,13 +1,14 @@ package keystore import ( + "context" "fmt" "strings" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) //go:generate mockery --quiet --name P2P --output ./mocks/ --case=underscore --filename p2p.go @@ -15,12 +16,12 @@ import ( type P2P interface { Get(id p2pkey.PeerID) (p2pkey.KeyV2, error) GetAll() ([]p2pkey.KeyV2, error) - Create() (p2pkey.KeyV2, error) - Add(key p2pkey.KeyV2) error - Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) - Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) + Create(ctx context.Context) (p2pkey.KeyV2, error) + Add(ctx context.Context, key p2pkey.KeyV2) error + Delete(ctx context.Context, id p2pkey.PeerID) (p2pkey.KeyV2, error) + Import(ctx context.Context, keyJSON []byte, password string) (p2pkey.KeyV2, error) Export(id p2pkey.PeerID, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) } @@ -58,7 +59,7 @@ func (ks *p2p) GetAll() (keys []p2pkey.KeyV2, _ error) { return keys, nil } -func (ks *p2p) Create() (p2pkey.KeyV2, error) { +func (ks *p2p) Create(ctx context.Context) (p2pkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -68,10 +69,10 @@ func (ks *p2p) Create() (p2pkey.KeyV2, error) { if err != nil { return p2pkey.KeyV2{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *p2p) Add(key p2pkey.KeyV2) error { +func (ks *p2p) Add(ctx context.Context, key p2pkey.KeyV2) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -80,10 +81,10 @@ func (ks *p2p) Add(key p2pkey.KeyV2) error { if _, found := ks.keyRing.P2P[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *p2p) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { +func (ks *p2p) Delete(ctx context.Context, id p2pkey.PeerID) (p2pkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -93,14 +94,14 @@ func (ks *p2p) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { if err != nil { return p2pkey.KeyV2{}, err } - err = ks.safeRemoveKey(key, func(tx pg.Queryer) error { - _, err2 := tx.Exec(`DELETE FROM p2p_peers WHERE peer_id = $1`, key.ID()) + err = ks.safeRemoveKey(ctx, key, func(ds sqlutil.DataSource) error { + _, err2 := ds.ExecContext(ctx, `DELETE FROM p2p_peers WHERE peer_id = $1`, key.ID()) return err2 }) return key, err } -func (ks *p2p) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { +func (ks *p2p) Import(ctx context.Context, keyJSON []byte, password string) (p2pkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -113,7 +114,7 @@ func (ks *p2p) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { if _, found := ks.keyRing.P2P[key.ID()]; found { return p2pkey.KeyV2{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *p2p) Export(id p2pkey.PeerID, password string) ([]byte, error) { @@ -129,7 +130,7 @@ func (ks *p2p) Export(id p2pkey.PeerID, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -func (ks *p2p) EnsureKey() error { +func (ks *p2p) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -147,7 +148,7 @@ func (ks *p2p) EnsureKey() error { ks.logger.Infof("Created P2P key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } var ( diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 4dc44651473..f6c86a12814 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "crypto/rand" "fmt" "testing" @@ -12,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -20,15 +20,15 @@ import ( func Test_P2PKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.P2P() reset := func() { + ctx := context.Background() // Executed on cleanup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -49,7 +49,8 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.PeerID()) require.NoError(t, err) @@ -58,7 +59,8 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.PeerID(), cltest.Password) require.NoError(t, err) @@ -67,15 +69,15 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.NoError(t, err) _, err = ks.Export(nonExistent, cltest.Password) assert.Error(t, err) - _, err = ks.Delete(key.PeerID()) + _, err = ks.Delete(ctx, key.PeerID()) require.NoError(t, err) _, err = ks.Get(key.PeerID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) - _, err = ks.Import(exportJSON, cltest.Password) + _, err = ks.Import(ctx, exportJSON, cltest.Password) assert.Error(t, err) - _, err = ks.Import([]byte(""), cltest.Password) + _, err = ks.Import(ctx, []byte(""), cltest.Password) assert.Error(t, err) require.Equal(t, key.PeerID(), importedKey.PeerID()) retrievedKey, err := ks.Get(key.PeerID()) @@ -85,18 +87,19 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := p2pkey.NewV2() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.PeerID()) + _, err = ks.Delete(ctx, newKey.PeerID()) require.NoError(t, err) - _, err = ks.Delete(newKey.PeerID()) + _, err = ks.Delete(ctx, newKey.PeerID()) assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -107,14 +110,15 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKey() + ctx := testutils.Context(t) + err := ks.EnsureKey(ctx) assert.NoError(t, err) keys, err := ks.GetAll() assert.NoError(t, err) require.Equal(t, 1, len(keys)) - err = ks.EnsureKey() + err = ks.EnsureKey(ctx) assert.NoError(t, err) keys, err = ks.GetAll() @@ -124,12 +128,13 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("GetOrFirst", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) _, err := ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "no p2p keys exist") id := p2pkey.PeerID{0xa0} _, err = ks.GetOrFirst(id) require.Contains(t, err.Error(), fmt.Sprintf("unable to find P2P key with id %s", id)) - k1, err := ks.Create() + k1, err := ks.Create(ctx) require.NoError(t, err) k2, err := ks.GetOrFirst(p2pkey.PeerID{}) require.NoError(t, err) @@ -137,7 +142,7 @@ func Test_P2PKeyStore_E2E(t *testing.T) { k3, err := ks.GetOrFirst(k1.PeerID()) require.NoError(t, err) require.Equal(t, k1, k3) - _, err = ks.Create() + _, err = ks.Create(ctx) require.NoError(t, err) _, err = ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "multiple p2p keys found") @@ -152,7 +157,8 @@ func Test_P2PKeyStore_E2E(t *testing.T) { }) t.Run("clears p2p_peers on delete", func(t *testing.T) { - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) type P2PPeer struct { ID string @@ -181,14 +187,15 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.NoError(t, stmt.Get(&p2pPeer1, &p2pPeer1)) require.NoError(t, stmt.Get(&p2pPeer2, &p2pPeer2)) cltest.AssertCount(t, db, p2pTableName, 2) - _, err = ks.Delete(key.PeerID()) + _, err = ks.Delete(ctx, key.PeerID()) require.NoError(t, err) cltest.AssertCount(t, db, p2pTableName, 1) }) t.Run("imports a key exported from a v1 keystore", func(t *testing.T) { + ctx := testutils.Context(t) exportedKey := `{"publicKey":"fcc1fdebde28322dde17233fe7bd6dcde447d60d5cc1de518962deed102eea35","peerID":"p2p_12D3KooWSq2UZgSXvhGLG5uuAAmz1JNjxHMJViJB39aorvbbYo8p","crypto":{"cipher":"aes-128-ctr","ciphertext":"adb2dff72148a8cd467f6f06a03869e7cedf180cf2a4decdb86875b2e1cf3e58c4bd2b721ecdaa88a0825fa9abfc309bf32dbb35a5c0b6cb01ac89a956d78e0550eff351","cipherparams":{"iv":"6cc4381766a4efc39f762b2b8d09dfba"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ff5055ae4cdcdc2d0404307d578262e2caeb0210f82db3a0ecbdba727c6f5259"},"mac":"d37e4f1dea98d85960ef3205099fc71741715ae56a3b1a8f9215a78de9b95595"}}` - importedKey, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_") + importedKey, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_") require.NoError(t, err) require.Equal(t, "12D3KooWSq2UZgSXvhGLG5uuAAmz1JNjxHMJViJB39aorvbbYo8p", importedKey.ID()) }) diff --git a/core/services/keystore/solana.go b/core/services/keystore/solana.go index 47b2cde7120..e95af37a7fa 100644 --- a/core/services/keystore/solana.go +++ b/core/services/keystore/solana.go @@ -14,12 +14,12 @@ import ( type Solana interface { Get(id string) (solkey.Key, error) GetAll() ([]solkey.Key, error) - Create() (solkey.Key, error) - Add(key solkey.Key) error - Delete(id string) (solkey.Key, error) - Import(keyJSON []byte, password string) (solkey.Key, error) + Create(ctx context.Context) (solkey.Key, error) + Add(ctx context.Context, key solkey.Key) error + Delete(ctx context.Context, id string) (solkey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (solkey.Key, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error Sign(ctx context.Context, id string, msg []byte) (signature []byte, err error) } @@ -72,7 +72,7 @@ func (ks *solana) GetAll() (keys []solkey.Key, _ error) { return keys, nil } -func (ks *solana) Create() (solkey.Key, error) { +func (ks *solana) Create(ctx context.Context) (solkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -82,10 +82,10 @@ func (ks *solana) Create() (solkey.Key, error) { if err != nil { return solkey.Key{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *solana) Add(key solkey.Key) error { +func (ks *solana) Add(ctx context.Context, key solkey.Key) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -94,10 +94,10 @@ func (ks *solana) Add(key solkey.Key) error { if _, found := ks.keyRing.Solana[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *solana) Delete(id string) (solkey.Key, error) { +func (ks *solana) Delete(ctx context.Context, id string) (solkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -107,11 +107,11 @@ func (ks *solana) Delete(id string) (solkey.Key, error) { if err != nil { return solkey.Key{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *solana) Import(keyJSON []byte, password string) (solkey.Key, error) { +func (ks *solana) Import(ctx context.Context, keyJSON []byte, password string) (solkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -124,7 +124,7 @@ func (ks *solana) Import(keyJSON []byte, password string) (solkey.Key, error) { if _, found := ks.keyRing.Solana[key.ID()]; found { return solkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *solana) Export(id string, password string) ([]byte, error) { @@ -140,7 +140,7 @@ func (ks *solana) Export(id string, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -func (ks *solana) EnsureKey() error { +func (ks *solana) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -157,7 +157,7 @@ func (ks *solana) EnsureKey() error { ks.logger.Infof("Created Solana key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } func (ks *solana) Sign(_ context.Context, id string, msg []byte) (signature []byte, err error) { diff --git a/core/services/keystore/solana_test.go b/core/services/keystore/solana_test.go index cf2515f5f70..7355404d093 100644 --- a/core/services/keystore/solana_test.go +++ b/core/services/keystore/solana_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -9,7 +10,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" @@ -17,15 +17,15 @@ import ( func Test_SolanaKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.Solana() reset := func() { + ctx := context.Background() // Executed on cleanup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -43,7 +43,8 @@ func Test_SolanaKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -52,21 +53,22 @@ func Test_SolanaKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) _, err = ks.Export("non-existent", cltest.Password) assert.Error(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) - _, err = ks.Import(exportJSON, cltest.Password) + _, err = ks.Import(ctx, exportJSON, cltest.Password) assert.Error(t, err) - _, err = ks.Import([]byte(""), cltest.Password) + _, err = ks.Import(ctx, []byte(""), cltest.Password) assert.Error(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -76,18 +78,19 @@ func Test_SolanaKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := solkey.New() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -98,10 +101,11 @@ func Test_SolanaKeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKey() + ctx := testutils.Context(t) + err := ks.EnsureKey(ctx) assert.NoError(t, err) - err = ks.EnsureKey() + err = ks.EnsureKey(ctx) assert.NoError(t, err) keys, err := ks.GetAll() @@ -111,9 +115,10 @@ func Test_SolanaKeyStore_E2E(t *testing.T) { t.Run("sign tx", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := solkey.New() require.NoError(t, err) - require.NoError(t, ks.Add(newKey)) + require.NoError(t, ks.Add(ctx, newKey)) // sign unknown ID _, err = ks.Sign(testutils.Context(t), "not-real", nil) diff --git a/core/services/keystore/starknet.go b/core/services/keystore/starknet.go index 6b6afa987c6..e6655a4d3f2 100644 --- a/core/services/keystore/starknet.go +++ b/core/services/keystore/starknet.go @@ -18,12 +18,12 @@ import ( type StarkNet interface { Get(id string) (starkkey.Key, error) GetAll() ([]starkkey.Key, error) - Create() (starkkey.Key, error) - Add(key starkkey.Key) error - Delete(id string) (starkkey.Key, error) - Import(keyJSON []byte, password string) (starkkey.Key, error) + Create(ctx context.Context) (starkkey.Key, error) + Add(ctx context.Context, key starkkey.Key) error + Delete(ctx context.Context, id string) (starkkey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (starkkey.Key, error) Export(id string, password string) ([]byte, error) - EnsureKey() error + EnsureKey(ctx context.Context) error } type starknet struct { @@ -59,7 +59,7 @@ func (ks *starknet) GetAll() (keys []starkkey.Key, _ error) { return keys, nil } -func (ks *starknet) Create() (starkkey.Key, error) { +func (ks *starknet) Create(ctx context.Context) (starkkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -69,10 +69,10 @@ func (ks *starknet) Create() (starkkey.Key, error) { if err != nil { return starkkey.Key{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *starknet) Add(key starkkey.Key) error { +func (ks *starknet) Add(ctx context.Context, key starkkey.Key) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -81,10 +81,10 @@ func (ks *starknet) Add(key starkkey.Key) error { if _, found := ks.keyRing.StarkNet[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *starknet) Delete(id string) (starkkey.Key, error) { +func (ks *starknet) Delete(ctx context.Context, id string) (starkkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -94,11 +94,11 @@ func (ks *starknet) Delete(id string) (starkkey.Key, error) { if err != nil { return starkkey.Key{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *starknet) Import(keyJSON []byte, password string) (starkkey.Key, error) { +func (ks *starknet) Import(ctx context.Context, keyJSON []byte, password string) (starkkey.Key, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -111,7 +111,7 @@ func (ks *starknet) Import(keyJSON []byte, password string) (starkkey.Key, error if _, found := ks.keyRing.StarkNet[key.ID()]; found { return starkkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *starknet) Export(id string, password string) ([]byte, error) { @@ -127,7 +127,7 @@ func (ks *starknet) Export(id string, password string) ([]byte, error) { return starkkey.ToEncryptedJSON(key, password, ks.scryptParams) } -func (ks *starknet) EnsureKey() error { +func (ks *starknet) EnsureKey(ctx context.Context) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -144,7 +144,7 @@ func (ks *starknet) EnsureKey() error { ks.logger.Infof("Created StarkNet key with ID %s", key.ID()) - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } func (ks *starknet) getByID(id string) (starkkey.Key, error) { diff --git a/core/services/keystore/starknet_test.go b/core/services/keystore/starknet_test.go index 43624a4159e..97d4219272b 100644 --- a/core/services/keystore/starknet_test.go +++ b/core/services/keystore/starknet_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "fmt" "math/big" "testing" @@ -14,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" @@ -25,15 +25,15 @@ import ( func Test_StarkNetKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.StarkNet() reset := func() { + ctx := context.Background() // Executed on cleanup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -51,7 +51,8 @@ func Test_StarkNetKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -60,15 +61,16 @@ func Test_StarkNetKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -78,14 +80,15 @@ func Test_StarkNetKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := starkkey.New() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -96,10 +99,11 @@ func Test_StarkNetKeyStore_E2E(t *testing.T) { t.Run("ensures key", func(t *testing.T) { defer reset() - err := ks.EnsureKey() + ctx := testutils.Context(t) + err := ks.EnsureKey(ctx) assert.NoError(t, err) - err = ks.EnsureKey() + err = ks.EnsureKey(ctx) assert.NoError(t, err) keys, err := ks.GetAll() diff --git a/core/services/keystore/vrf.go b/core/services/keystore/vrf.go index 91e77557674..7b222e193d1 100644 --- a/core/services/keystore/vrf.go +++ b/core/services/keystore/vrf.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "math/big" @@ -14,10 +15,10 @@ import ( type VRF interface { Get(id string) (vrfkey.KeyV2, error) GetAll() ([]vrfkey.KeyV2, error) - Create() (vrfkey.KeyV2, error) - Add(key vrfkey.KeyV2) error - Delete(id string) (vrfkey.KeyV2, error) - Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) + Create(ctx context.Context) (vrfkey.KeyV2, error) + Add(ctx context.Context, key vrfkey.KeyV2) error + Delete(ctx context.Context, id string) (vrfkey.KeyV2, error) + Import(ctx context.Context, keyJSON []byte, password string) (vrfkey.KeyV2, error) Export(id string, password string) ([]byte, error) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) @@ -60,7 +61,7 @@ func (ks *vrf) GetAll() (keys []vrfkey.KeyV2, _ error) { return keys, nil } -func (ks *vrf) Create() (vrfkey.KeyV2, error) { +func (ks *vrf) Create(ctx context.Context) (vrfkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -70,10 +71,10 @@ func (ks *vrf) Create() (vrfkey.KeyV2, error) { if err != nil { return vrfkey.KeyV2{}, err } - return key, ks.safeAddKey(key) + return key, ks.safeAddKey(ctx, key) } -func (ks *vrf) Add(key vrfkey.KeyV2) error { +func (ks *vrf) Add(ctx context.Context, key vrfkey.KeyV2) error { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -82,10 +83,10 @@ func (ks *vrf) Add(key vrfkey.KeyV2) error { if _, found := ks.keyRing.VRF[key.ID()]; found { return fmt.Errorf("key with ID %s already exists", key.ID()) } - return ks.safeAddKey(key) + return ks.safeAddKey(ctx, key) } -func (ks *vrf) Delete(id string) (vrfkey.KeyV2, error) { +func (ks *vrf) Delete(ctx context.Context, id string) (vrfkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -95,11 +96,11 @@ func (ks *vrf) Delete(id string) (vrfkey.KeyV2, error) { if err != nil { return vrfkey.KeyV2{}, err } - err = ks.safeRemoveKey(key) + err = ks.safeRemoveKey(ctx, key) return key, err } -func (ks *vrf) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { +func (ks *vrf) Import(ctx context.Context, keyJSON []byte, password string) (vrfkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -112,7 +113,7 @@ func (ks *vrf) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { if _, found := ks.keyRing.VRF[key.ID()]; found { return vrfkey.KeyV2{}, fmt.Errorf("key with ID %s already exists", key.ID()) } - return key, ks.keyManager.safeAddKey(key) + return key, ks.keyManager.safeAddKey(ctx, key) } func (ks *vrf) Export(id string, password string) ([]byte, error) { diff --git a/core/services/keystore/vrf_test.go b/core/services/keystore/vrf_test.go index 77fccd865ff..4b77377d5e8 100644 --- a/core/services/keystore/vrf_test.go +++ b/core/services/keystore/vrf_test.go @@ -1,6 +1,7 @@ package keystore_test import ( + "context" "fmt" "math/big" "testing" @@ -9,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" @@ -19,14 +20,14 @@ import ( func Test_VRFKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := keystore.ExposedNewMaster(t, db, cfg.Database()) - require.NoError(t, keyStore.Unlock(cltest.Password)) + keyStore := keystore.ExposedNewMaster(t, db) + require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) ks := keyStore.VRF() reset := func() { + ctx := context.Background() // Executed during cleanup require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(cltest.Password)) + require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } t.Run("initializes with an empty state", func(t *testing.T) { @@ -44,7 +45,8 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("creates a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -53,15 +55,16 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("imports and exports a key", func(t *testing.T) { defer reset() - key, err := ks.Create() + ctx := testutils.Context(t) + key, err := ks.Create(ctx) require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) @@ -71,14 +74,15 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) newKey, err := vrfkey.NewV2() require.NoError(t, err) - err = ks.Add(newKey) + err = ks.Add(ctx, newKey) require.NoError(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) keys, err = ks.GetAll() require.NoError(t, err) @@ -89,13 +93,14 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("fails to add an already added key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) k, err := vrfkey.NewV2() require.NoError(t, err) - err = ks.Add(k) + err = ks.Add(ctx, k) require.NoError(t, err) - err = ks.Add(k) + err = ks.Add(ctx, k) assert.Error(t, err) assert.Equal(t, fmt.Sprintf("key with ID %s already exists", k.ID()), err.Error()) @@ -103,14 +108,15 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("fails to delete a key that doesn't exists", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) k, err := vrfkey.NewV2() require.NoError(t, err) - err = ks.Add(k) + err = ks.Add(ctx, k) require.NoError(t, err) - fk, err := ks.Delete("non-existent") + fk, err := ks.Delete(ctx, "non-existent") assert.Zero(t, fk) assert.Error(t, err) @@ -118,22 +124,24 @@ func Test_VRFKeyStore_E2E(t *testing.T) { t.Run("imports a key exported from a v1 keystore", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) exportedKey := `{"PublicKey":"0xd2377bc6be8a2c5ce163e1867ee42ef111e320686f940a98e52e9c019ca0606800","vrf_key":{"address":"b94276ad4e5452732ec0cccf30ef7919b67844b6","crypto":{"cipher":"aes-128-ctr","ciphertext":"ff66d61d02dba54a61bab1ceb8414643f9e76b7351785d2959e2c8b50ee69a92","cipherparams":{"iv":"75705da271b11e330a27b8d593a3930c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"efe5b372e4fe79d0af576a79d65a1ee35d0792d9c92b70107b5ada1817ea7c7b"},"mac":"e4d0bb08ffd004ab03aeaa42367acbd9bb814c6cfd981f5157503f54c30816e7"},"version":3}}` - importedKey, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_") + importedKey, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_") require.NoError(t, err) require.Equal(t, "0xd2377bc6be8a2c5ce163e1867ee42ef111e320686f940a98e52e9c019ca0606800", importedKey.ID()) }) t.Run("fails to import an already imported key", func(t *testing.T) { defer reset() + ctx := testutils.Context(t) exportedKey := `{"PublicKey":"0xd2377bc6be8a2c5ce163e1867ee42ef111e320686f940a98e52e9c019ca0606800","vrf_key":{"address":"b94276ad4e5452732ec0cccf30ef7919b67844b6","crypto":{"cipher":"aes-128-ctr","ciphertext":"ff66d61d02dba54a61bab1ceb8414643f9e76b7351785d2959e2c8b50ee69a92","cipherparams":{"iv":"75705da271b11e330a27b8d593a3930c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"efe5b372e4fe79d0af576a79d65a1ee35d0792d9c92b70107b5ada1817ea7c7b"},"mac":"e4d0bb08ffd004ab03aeaa42367acbd9bb814c6cfd981f5157503f54c30816e7"},"version":3}}` - importedKey, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_") + importedKey, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_") require.NoError(t, err) keyStore.SetPassword("p4SsW0rD1!@#_") - k, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_") + k, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_") assert.Zero(t, k) assert.Error(t, err) @@ -158,9 +166,10 @@ func Test_VRFKeyStore_E2E(t *testing.T) { }) t.Run("generates a proof for a key", func(t *testing.T) { + ctx := testutils.Context(t) k, err := vrfkey.NewV2() require.NoError(t, err) - err = ks.Add(k) + err = ks.Add(ctx, k) require.NoError(t, err) pf, err := ks.GenerateProof(k.ID(), big.NewInt(int64(1))) diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index 2572efb1822..09be8c23453 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr/config.go b/core/services/ocr/config.go index 53ec9f9cea9..0dca9e83b3c 100644 --- a/core/services/ocr/config.go +++ b/core/services/ocr/config.go @@ -4,13 +4,15 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // Config contains OCR configurations for a job. type Config interface { - pg.QConfig + Insecure() config.Insecure + JobPipeline() config.JobPipeline + OCR() config.OCR } func toLocalConfig(cfg ValidationConfig, evmOcrConfig evmconfig.OCR, insecureCfg insecureConfig, spec job.OCROracleSpec, ocrConfig job.OCRConfig) ocrtypes.LocalConfig { diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index e4845ee3bc2..5746f97cd38 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -14,13 +14,12 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/config" @@ -31,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // configMailboxSanityLimit is the maximum number of configs that can be held @@ -64,7 +62,7 @@ type ( jobID int32 logger logger.Logger ocrDB OCRContractTrackerDB - q pg.Q + ds sqlutil.DataSource blockTranslator ocrcommon.BlockTranslator cfg ocrcommon.Config mailMon *mailbox.Monitor @@ -92,8 +90,8 @@ type ( } OCRContractTrackerDB interface { - SaveLatestRoundRequested(tx pg.Queryer, rr offchainaggregator.OffchainAggregatorRoundRequested) error - LoadLatestRoundRequested() (rr offchainaggregator.OffchainAggregatorRoundRequested, err error) + SaveLatestRoundRequested(ctx context.Context, tx sqlutil.DataSource, rr offchainaggregator.OffchainAggregatorRoundRequested) error + LoadLatestRoundRequested(ctx context.Context) (rr offchainaggregator.OffchainAggregatorRoundRequested, err error) } ) @@ -112,10 +110,9 @@ func NewOCRContractTracker( logBroadcaster log.Broadcaster, jobID int32, logger logger.Logger, - db *sqlx.DB, + ds sqlutil.DataSource, ocrDB OCRContractTrackerDB, cfg ocrcommon.Config, - q pg.QConfig, headBroadcaster httypes.HeadBroadcaster, mailMon *mailbox.Monitor, ) (o *OCRContractTracker) { @@ -129,7 +126,7 @@ func NewOCRContractTracker( jobID: jobID, logger: logger, ocrDB: ocrDB, - q: pg.NewQ(db, logger, q), + ds: ds, blockTranslator: ocrcommon.NewBlockTranslator(cfg, ethClient, logger), cfg: cfg, mailMon: mailMon, @@ -144,9 +141,9 @@ func NewOCRContractTracker( // Start must be called before logs can be delivered // It ought to be called before starting OCR -func (t *OCRContractTracker) Start(context.Context) error { +func (t *OCRContractTracker) Start(ctx context.Context) error { return t.StartOnce("OCRContractTracker", func() (err error) { - t.latestRoundRequested, err = t.ocrDB.LoadLatestRoundRequested() + t.latestRoundRequested, err = t.ocrDB.LoadLatestRoundRequested(ctx) if err != nil { return errors.Wrap(err, "OCRContractTracker#Start: failed to load latest round requested") } @@ -240,10 +237,7 @@ func (t *OCRContractTracker) processLogs() { // HandleLog complies with LogListener interface // It is not thread safe -func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { - ctx, cancel := t.chStop.NewCtx() - defer cancel() - +func (t *OCRContractTracker) HandleLog(ctx context.Context, lb log.Broadcast) { was, err := t.logBroadcaster.WasAlreadyConsumed(ctx, lb) if err != nil { t.logger.Errorw("could not determine if log was already consumed", "err", err) @@ -255,14 +249,14 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { raw := lb.RawLog() if raw.Address != t.contract.Address() { t.logger.Errorf("log address of 0x%x does not match configured contract address of 0x%x", raw.Address, t.contract.Address()) - if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, nil, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return } topics := raw.Topics if len(topics) == 0 { - if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, nil, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return @@ -275,7 +269,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { configSet, err = t.contractFilterer.ParseConfigSet(raw) if err != nil { t.logger.Errorw("could not parse config set", "err", err) - if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, nil, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return @@ -292,17 +286,17 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { rr, err = t.contractFilterer.ParseRoundRequested(raw) if err != nil { t.logger.Errorw("could not parse round requested", "err", err) - if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, nil, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return } if IsLaterThan(raw, t.latestRoundRequested.Raw) { - err = t.q.Transaction(func(tx pg.Queryer) error { - if err = t.ocrDB.SaveLatestRoundRequested(tx, *rr); err != nil { + err = sqlutil.TransactDataSource(ctx, t.ds, nil, func(tx sqlutil.DataSource) error { + if err = t.ocrDB.SaveLatestRoundRequested(ctx, tx, *rr); err != nil { return err } - return t.logBroadcaster.MarkConsumed(ctx, lb) + return t.logBroadcaster.MarkConsumed(ctx, tx, lb) }) if err != nil { t.logger.Error(err) @@ -320,7 +314,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { t.logger.Debugw("got unrecognised log topic", "topic", topics[0]) } if !consumed { - if err := t.logBroadcaster.MarkConsumed(ctx, lb); err != nil { + if err := t.logBroadcaster.MarkConsumed(ctx, nil, lb); err != nil { t.logger.Errorw("failed to mark log consumed", "err", err) } } diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index 678af35fa04..6f8b05c6436 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -20,7 +20,6 @@ import ( htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" @@ -55,13 +54,10 @@ type contractTrackerUni struct { } func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrackerUni) { - var cfg evmconfig.ChainScopedConfig var filterer *offchainaggregator.OffchainAggregatorFilterer var contract *offchain_aggregator_wrapper.OffchainAggregator for _, opt := range opts { switch v := opt.(type) { - case evmconfig.ChainScopedConfig: - cfg = v case *offchainaggregator.OffchainAggregatorFilterer: filterer = v case *offchain_aggregator_wrapper.OffchainAggregator: @@ -70,9 +66,8 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack t.Fatalf("unrecognised option type %T", v) } } - if cfg == nil { - cfg = evmtest.NewChainScopedConfig(t, configtest.NewTestGeneralConfig(t)) - } + gcfg := configtest.NewTestGeneralConfig(t) + cfg := evmtest.NewChainScopedConfig(t, gcfg) if filterer == nil { filterer = mustNewFilterer(t) } @@ -97,7 +92,6 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack db, uni.db, cfg.EVM(), - cfg.Database(), uni.hb, mailMon, ) @@ -146,7 +140,7 @@ func Test_OCRContractTracker_LatestBlockHeight(t *testing.T) { uni := newContractTrackerUni(t) uni.hb.On("Subscribe", uni.tracker).Return(&evmtypes.Head{Number: 42}, func() {}) - uni.db.On("LoadLatestRoundRequested").Return(offchainaggregator.OffchainAggregatorRoundRequested{}, nil) + uni.db.On("LoadLatestRoundRequested", mock.Anything).Return(offchainaggregator.OffchainAggregatorRoundRequested{}, nil) uni.lb.On("Register", uni.tracker, mock.Anything).Return(func() {}) servicetest.Run(t, uni.tracker) @@ -172,7 +166,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin rawLog := cltest.LogFromFixture(t, "../../testdata/jsonrpc/round_requested_log_1_1.json") logBroadcast.On("RawLog").Return(rawLog).Maybe() logBroadcast.On("String").Return("").Maybe() - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) configDigest, epoch, round, err := uni.tracker.LatestRoundRequested(testutils.Context(t), 0) @@ -181,7 +175,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin require.Equal(t, 0, int(round)) require.Equal(t, 0, int(epoch)) - uni.tracker.HandleLog(logBroadcast) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -203,7 +197,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin require.Equal(t, 0, int(round)) require.Equal(t, 0, int(epoch)) - uni.tracker.HandleLog(logBroadcast) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -228,13 +222,13 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast.On("RawLog").Return(rawLog).Maybe() logBroadcast.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { + uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { return rr.Epoch == 1 && rr.Round == 1 })).Return(nil) - uni.tracker.HandleLog(logBroadcast) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -248,13 +242,13 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast2.On("RawLog").Return(rawLog2) logBroadcast2.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { + uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { return rr.Epoch == 1 && rr.Round == 9 })).Return(nil) - uni.tracker.HandleLog(logBroadcast2) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast2) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -263,7 +257,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin assert.Equal(t, 9, int(round)) // Same round with lower epoch is ignored - uni.tracker.HandleLog(logBroadcast) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -277,13 +271,13 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast3.On("RawLog").Return(rawLog3).Maybe() logBroadcast3.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { + uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything, mock.MatchedBy(func(rr offchainaggregator.OffchainAggregatorRoundRequested) bool { return rr.Epoch == 2 && rr.Round == 1 })).Return(nil) - uni.tracker.HandleLog(logBroadcast3) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast3) configDigest, epoch, round, err = uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -301,9 +295,9 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything).Return(errors.New("something exploded")) + uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("something exploded")) - uni.tracker.HandleLog(logBroadcast) + uni.tracker.HandleLog(testutils.Context(t), logBroadcast) configDigest, epoch, round, err := uni.tracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -331,7 +325,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin eventuallyCloseHeadBroadcaster := cltest.NewAwaiter() uni.hb.On("Subscribe", uni.tracker).Return((*evmtypes.Head)(nil), func() { eventuallyCloseHeadBroadcaster.ItHappened() }) - uni.db.On("LoadLatestRoundRequested").Return(rr, nil) + uni.db.On("LoadLatestRoundRequested", mock.Anything).Return(rr, nil) require.NoError(t, uni.tracker.Start(testutils.Context(t))) diff --git a/core/services/ocr/database.go b/core/services/ocr/database.go index 977c371c15d..95993de9d5c 100644 --- a/core/services/ocr/database.go +++ b/core/services/ocr/database.go @@ -11,17 +11,16 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/jmoiron/sqlx" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type db struct { - q pg.Q + ds sqlutil.DataSource oracleSpecID int32 lggr logger.SugaredLogger } @@ -32,11 +31,9 @@ var ( ) // NewDB returns a new DB scoped to this oracleSpecID -func NewDB(sqlxDB *sqlx.DB, oracleSpecID int32, lggr logger.Logger, cfg pg.QConfig) *db { - namedLogger := lggr.Named("OCR.DB") - +func NewDB(ds sqlutil.DataSource, oracleSpecID int32, lggr logger.Logger) *db { return &db{ - q: pg.NewQ(sqlxDB, namedLogger, cfg), + ds: ds, oracleSpecID: oracleSpecID, lggr: logger.Sugared(lggr), } @@ -54,7 +51,7 @@ func (d *db) ReadState(ctx context.Context, cd ocrtypes.ConfigDigest) (ps *ocrty var tmp []int64 var highestSentEpochTmp int64 - err = d.q.QueryRowxContext(ctx, stmt, d.oracleSpecID, cd).Scan(&ps.Epoch, &highestSentEpochTmp, pq.Array(&tmp)) + err = d.ds.QueryRowxContext(ctx, stmt, d.oracleSpecID, cd).Scan(&ps.Epoch, &highestSentEpochTmp, pq.Array(&tmp)) if errors.Is(err, sql.ErrNoRows) { return nil, nil } @@ -90,7 +87,9 @@ func (d *db) WriteState(ctx context.Context, cd ocrtypes.ConfigDigest, state ocr NOW() ) ` - _, err := d.q.WithOpts(pg.WithLongQueryTimeout()).ExecContext( + ctx, cancel := context.WithTimeout(sqlutil.WithoutDefaultTimeout(ctx), time.Minute) + defer cancel() + _, err := d.ds.ExecContext( ctx, stmt, d.oracleSpecID, cd, state.Epoch, state.HighestSentEpoch, pq.Array(&highestReceivedEpoch), ) @@ -109,7 +108,7 @@ func (d *db) ReadConfig(ctx context.Context) (c *ocrtypes.ContractConfig, err er var signers [][]byte var transmitters [][]byte - err = d.q.QueryRowContext(ctx, stmt, d.oracleSpecID).Scan( + err = d.ds.QueryRowxContext(ctx, stmt, d.oracleSpecID).Scan( &c.ConfigDigest, (*pq.ByteaArray)(&signers), (*pq.ByteaArray)(&transmitters), @@ -155,7 +154,7 @@ func (d *db) WriteConfig(ctx context.Context, c ocrtypes.ContractConfig) error { encoded = EXCLUDED.encoded, updated_at = NOW() ` - _, err := d.q.ExecContext(ctx, stmt, d.oracleSpecID, c.ConfigDigest, pq.ByteaArray(signers), pq.ByteaArray(transmitters), c.Threshold, int(c.EncodedConfigVersion), c.Encoded) + _, err := d.ds.ExecContext(ctx, stmt, d.oracleSpecID, c.ConfigDigest, pq.ByteaArray(signers), pq.ByteaArray(transmitters), c.Threshold, int(c.EncodedConfigVersion), c.Encoded) return errors.Wrap(err, "WriteConfig failed") } @@ -201,14 +200,14 @@ func (d *db) StorePendingTransmission(ctx context.Context, k ocrtypes.ReportTime updated_at = NOW() ` - _, err := d.q.ExecContext(ctx, stmt, d.oracleSpecID, k.ConfigDigest, k.Epoch, k.Round, p.Time, median, p.SerializedReport, pq.ByteaArray(rs), pq.ByteaArray(ss), p.Vs[:]) + _, err := d.ds.ExecContext(ctx, stmt, d.oracleSpecID, k.ConfigDigest, k.Epoch, k.Round, p.Time, median, p.SerializedReport, pq.ByteaArray(rs), pq.ByteaArray(ss), p.Vs[:]) return errors.Wrap(err, "StorePendingTransmission failed") } func (d *db) PendingTransmissionsWithConfigDigest(ctx context.Context, cd ocrtypes.ConfigDigest) (map[ocrtypes.ReportTimestamp]ocrtypes.PendingTransmission, error) { //nolint sqlclosecheck false positive - rows, err := d.q.QueryContext(ctx, ` + rows, err := d.ds.QueryContext(ctx, ` SELECT config_digest, epoch, @@ -269,7 +268,9 @@ WHERE ocr_oracle_spec_id = $1 AND config_digest = $2 } func (d *db) DeletePendingTransmission(ctx context.Context, k ocrtypes.ReportTimestamp) (err error) { - _, err = d.q.WithOpts(pg.WithLongQueryTimeout()).ExecContext(ctx, ` + ctx, cancel := context.WithTimeout(sqlutil.WithoutDefaultTimeout(ctx), time.Minute) + defer cancel() + _, err = d.ds.ExecContext(ctx, ` DELETE FROM ocr_pending_transmissions WHERE ocr_oracle_spec_id = $1 AND config_digest = $2 AND epoch = $3 AND round = $4 `, d.oracleSpecID, k.ConfigDigest, k.Epoch, k.Round) @@ -280,7 +281,9 @@ WHERE ocr_oracle_spec_id = $1 AND config_digest = $2 AND epoch = $3 AND round = } func (d *db) DeletePendingTransmissionsOlderThan(ctx context.Context, t time.Time) (err error) { - _, err = d.q.WithOpts(pg.WithLongQueryTimeout()).ExecContext(ctx, ` + ctx, cancel := context.WithTimeout(sqlutil.WithoutDefaultTimeout(ctx), time.Minute) + defer cancel() + _, err = d.ds.ExecContext(ctx, ` DELETE FROM ocr_pending_transmissions WHERE ocr_oracle_spec_id = $1 AND time < $2 `, d.oracleSpecID, t) @@ -290,12 +293,12 @@ WHERE ocr_oracle_spec_id = $1 AND time < $2 return } -func (d *db) SaveLatestRoundRequested(tx pg.Queryer, rr offchainaggregator.OffchainAggregatorRoundRequested) error { +func (d *db) SaveLatestRoundRequested(ctx context.Context, tx sqlutil.DataSource, rr offchainaggregator.OffchainAggregatorRoundRequested) error { rawLog, err := json.Marshal(rr.Raw) if err != nil { return errors.Wrap(err, "could not marshal log as JSON") } - _, err = tx.Exec(` + _, err = tx.ExecContext(ctx, ` INSERT INTO ocr_latest_round_requested (ocr_oracle_spec_id, requester, config_digest, epoch, round, raw) VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (ocr_oracle_spec_id) DO UPDATE SET requester = EXCLUDED.requester, @@ -308,8 +311,8 @@ VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (ocr_oracle_spec_id) DO UPDATE SET return errors.Wrap(err, "could not save latest round requested") } -func (d *db) LoadLatestRoundRequested() (rr offchainaggregator.OffchainAggregatorRoundRequested, err error) { - rows, err := d.q.Query(` +func (d *db) LoadLatestRoundRequested(ctx context.Context) (rr offchainaggregator.OffchainAggregatorRoundRequested, err error) { + rows, err := d.ds.QueryContext(ctx, ` SELECT requester, config_digest, epoch, round, raw FROM ocr_latest_round_requested WHERE ocr_oracle_spec_id = $1 diff --git a/core/services/ocr/database_test.go b/core/services/ocr/database_test.go index 5ccf257b2bb..a2559ca2a87 100644 --- a/core/services/ocr/database_test.go +++ b/core/services/ocr/database_test.go @@ -16,7 +16,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/ocr" ) @@ -25,8 +24,7 @@ func Test_DB_ReadWriteState(t *testing.T) { db := pgtest.NewSqlxDB(t) configDigest := cltest.MakeConfigDigest(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) spec := cltest.MustInsertOffchainreportingOracleSpec(t, db, key.EIP55Address) @@ -106,7 +104,6 @@ func Test_DB_ReadWriteState(t *testing.T) { func Test_DB_ReadWriteConfig(t *testing.T) { db := pgtest.NewSqlxDB(t) sqlDB := db - cfg := configtest.NewTestGeneralConfig(t) config := ocrtypes.ContractConfig{ ConfigDigest: cltest.MakeConfigDigest(t), @@ -116,7 +113,7 @@ func Test_DB_ReadWriteConfig(t *testing.T) { EncodedConfigVersion: uint64(987654), Encoded: []byte{1, 2, 3, 4, 5}, } - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) spec := cltest.MustInsertOffchainreportingOracleSpec(t, db, key.EIP55Address) transmitterAddress := key.Address @@ -188,8 +185,7 @@ func assertPendingTransmissionEqual(t *testing.T, pt1, pt2 ocrtypes.PendingTrans func Test_DB_PendingTransmissions(t *testing.T) { db := pgtest.NewSqlxDB(t) sqlDB := db - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) spec := cltest.MustInsertOffchainreportingOracleSpec(t, db, key.EIP55Address) @@ -410,7 +406,8 @@ func Test_DB_LatestRoundRequested(t *testing.T) { } t.Run("saves latest round requested", func(t *testing.T) { - err := odb.SaveLatestRoundRequested(sqlDB, rr) + ctx := testutils.Context(t) + err := odb.SaveLatestRoundRequested(ctx, sqlDB, rr) require.NoError(t, err) rawLog.Index = 42 @@ -424,17 +421,18 @@ func Test_DB_LatestRoundRequested(t *testing.T) { Raw: rawLog, } - err = odb.SaveLatestRoundRequested(sqlDB, rr) + err = odb.SaveLatestRoundRequested(ctx, sqlDB, rr) require.NoError(t, err) }) t.Run("loads latest round requested", func(t *testing.T) { + ctx := testutils.Context(t) // There is no round for db2 - lrr, err := odb2.LoadLatestRoundRequested() + lrr, err := odb2.LoadLatestRoundRequested(ctx) require.NoError(t, err) require.Equal(t, 0, int(lrr.Epoch)) - lrr, err = odb.LoadLatestRoundRequested() + lrr, err = odb.LoadLatestRoundRequested(ctx) require.NoError(t, err) assert.Equal(t, rr, lrr) diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index bcdda397e20..88561bd1c3a 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -12,13 +12,13 @@ import ( "github.com/jmoiron/sqlx" - commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -28,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" @@ -82,10 +81,10 @@ func (d *Delegate) JobType() job.Type { return job.OffchainReporting } -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(spec job.Job) {} +func (d *Delegate) AfterJobCreated(spec job.Job) {} +func (d *Delegate) BeforeJobDeleted(spec job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec returns the OCR services that need to run for this job func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { @@ -96,7 +95,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] if err != nil { return nil, err } - concreteSpec, err := job.LoadConfigVarsOCR(chain.Config().EVM().OCR(), chain.Config().OCR(), *jb.OCROracleSpec) + concreteSpec, err := job.LoadConfigVarsOCR(chain.Config().EVM().OCR(), d.cfg.OCR(), *jb.OCROracleSpec) if err != nil { return nil, err } @@ -121,7 +120,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] return nil, errors.Wrap(err, "could not instantiate NewOffchainAggregatorCaller") } - ocrDB := NewDB(d.db, concreteSpec.ID, lggr, d.cfg) + ocrDB := NewDB(d.db, concreteSpec.ID, lggr) tracker := NewOCRContractTracker( contract, @@ -134,7 +133,6 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] d.db, ocrDB, chain.Config().EVM(), - chain.Config().Database(), chain.HeadBroadcaster(), d.mailMon, ) @@ -158,11 +156,11 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] v2Bootstrappers = peerWrapper.P2PConfig().V2().DefaultBootstrappers() } - ocrLogger := commonlogger.NewOCRWrapper(lggr, chain.Config().OCR().TraceLogging(), func(msg string) { + ocrLogger := commonlogger.NewOCRWrapper(lggr, d.cfg.OCR().TraceLogging(), func(msg string) { d.jobORM.TryRecordError(jb.ID, msg) }) - lc := toLocalConfig(chain.Config().EVM(), chain.Config().EVM().OCR(), chain.Config().Insecure(), *concreteSpec, chain.Config().OCR()) + lc := toLocalConfig(chain.Config().EVM(), chain.Config().EVM().OCR(), d.cfg.Insecure(), *concreteSpec, d.cfg.OCR()) if err = ocr.SanityCheckLocalConfig(lc); err != nil { return nil, err } @@ -198,11 +196,10 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] return nil, errors.Wrap(err, "could not get contract ABI JSON") } - cfg := chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(jb.ExternalJobID, cfg.OCR().DefaultTransactionQueueDepth(), cfg.Database().DefaultQueryTimeout()) + strategy := txmgrcommon.NewQueueingTxStrategy(jb.ExternalJobID, d.cfg.OCR().DefaultTransactionQueueDepth()) var checker txmgr.TransmitCheckerSpec - if chain.Config().OCR().SimulateTransactions() { + if d.cfg.OCR().SimulateTransactions() { checker.CheckerType = txmgr.TransmitCheckerTypeSimulate } @@ -256,8 +253,8 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] saver := ocrcommon.NewResultRunSaver( d.pipelineRunner, lggr, - cfg.JobPipeline().MaxSuccessfulRuns(), - cfg.JobPipeline().ResultWriteQueueDepth(), + d.cfg.JobPipeline().MaxSuccessfulRuns(), + d.cfg.JobPipeline().ResultWriteQueueDepth(), ) var configOverrider ocrtypes.ConfigOverrider @@ -279,7 +276,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] configOverrider = configOverriderService } - jb.OCROracleSpec.CaptureEATelemetry = chain.Config().OCR().CaptureEATelemetry() + jb.OCROracleSpec.CaptureEATelemetry = d.cfg.OCR().CaptureEATelemetry() enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) diff --git a/core/services/ocr/helpers_internal_test.go b/core/services/ocr/helpers_internal_test.go index 57b669ef401..c6a3d1ac401 100644 --- a/core/services/ocr/helpers_internal_test.go +++ b/core/services/ocr/helpers_internal_test.go @@ -5,7 +5,6 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -14,5 +13,5 @@ func (c *ConfigOverriderImpl) ExportedUpdateFlagsStatus() error { } func NewTestDB(t *testing.T, sqldb *sqlx.DB, oracleSpecID int32) *db { - return NewDB(sqldb, oracleSpecID, logger.TestLogger(t), pgtest.NewQConfig(true)) + return NewDB(sqldb, oracleSpecID, logger.TestLogger(t)) } diff --git a/core/services/ocr/mocks/ocr_contract_tracker_db.go b/core/services/ocr/mocks/ocr_contract_tracker_db.go index 6724e418014..ed47d87cd1e 100644 --- a/core/services/ocr/mocks/ocr_contract_tracker_db.go +++ b/core/services/ocr/mocks/ocr_contract_tracker_db.go @@ -1,13 +1,15 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks import ( + context "context" + mock "github.com/stretchr/testify/mock" offchainaggregator "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) // OCRContractTrackerDB is an autogenerated mock type for the OCRContractTrackerDB type @@ -15,9 +17,9 @@ type OCRContractTrackerDB struct { mock.Mock } -// LoadLatestRoundRequested provides a mock function with given fields: -func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.OffchainAggregatorRoundRequested, error) { - ret := _m.Called() +// LoadLatestRoundRequested provides a mock function with given fields: ctx +func (_m *OCRContractTrackerDB) LoadLatestRoundRequested(ctx context.Context) (offchainaggregator.OffchainAggregatorRoundRequested, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for LoadLatestRoundRequested") @@ -25,17 +27,17 @@ func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.O var r0 offchainaggregator.OffchainAggregatorRoundRequested var r1 error - if rf, ok := ret.Get(0).(func() (offchainaggregator.OffchainAggregatorRoundRequested, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (offchainaggregator.OffchainAggregatorRoundRequested, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() offchainaggregator.OffchainAggregatorRoundRequested); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) offchainaggregator.OffchainAggregatorRoundRequested); ok { + r0 = rf(ctx) } else { r0 = ret.Get(0).(offchainaggregator.OffchainAggregatorRoundRequested) } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -43,17 +45,17 @@ func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.O return r0, r1 } -// SaveLatestRoundRequested provides a mock function with given fields: tx, rr -func (_m *OCRContractTrackerDB) SaveLatestRoundRequested(tx pg.Queryer, rr offchainaggregator.OffchainAggregatorRoundRequested) error { - ret := _m.Called(tx, rr) +// SaveLatestRoundRequested provides a mock function with given fields: ctx, tx, rr +func (_m *OCRContractTrackerDB) SaveLatestRoundRequested(ctx context.Context, tx sqlutil.DataSource, rr offchainaggregator.OffchainAggregatorRoundRequested) error { + ret := _m.Called(ctx, tx, rr) if len(ret) == 0 { panic("no return value specified for SaveLatestRoundRequested") } var r0 error - if rf, ok := ret.Get(0).(func(pg.Queryer, offchainaggregator.OffchainAggregatorRoundRequested) error); ok { - r0 = rf(tx, rr) + if rf, ok := ret.Get(0).(func(context.Context, sqlutil.DataSource, offchainaggregator.OffchainAggregatorRoundRequested) error); ok { + r0 = rf(ctx, tx, rr) } else { r0 = ret.Error(0) } diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index a0f2353eac1..a31994f891a 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -14,10 +14,16 @@ import ( evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) +type GeneralConfig interface { + OCR() coreconfig.OCR + Insecure() coreconfig.Insecure +} + type ValidationConfig interface { ChainType() config.ChainType } @@ -37,8 +43,8 @@ type insecureConfig interface { } // ValidatedOracleSpecToml validates an oracle spec that came from TOML -func ValidatedOracleSpecToml(legacyChains legacyevm.LegacyChainContainer, tomlString string) (job.Job, error) { - return ValidatedOracleSpecTomlCfg(func(id *big.Int) (evmconfig.ChainScopedConfig, error) { +func ValidatedOracleSpecToml(gcfg GeneralConfig, legacyChains legacyevm.LegacyChainContainer, tomlString string) (job.Job, error) { + return ValidatedOracleSpecTomlCfg(gcfg, func(id *big.Int) (evmconfig.ChainScopedConfig, error) { c, err := legacyChains.Get(id.String()) if err != nil { return nil, err @@ -47,7 +53,7 @@ func ValidatedOracleSpecToml(legacyChains legacyevm.LegacyChainContainer, tomlSt }, tomlString) } -func ValidatedOracleSpecTomlCfg(configFn func(id *big.Int) (evmconfig.ChainScopedConfig, error), tomlString string) (job.Job, error) { +func ValidatedOracleSpecTomlCfg(gcfg GeneralConfig, configFn func(id *big.Int) (evmconfig.ChainScopedConfig, error), tomlString string) (job.Job, error) { var jb = job.Job{} var spec job.OCROracleSpec tree, err := toml.Load(tomlString) @@ -94,10 +100,10 @@ func ValidatedOracleSpecTomlCfg(configFn func(id *big.Int) (evmconfig.ChainScope if err := validateBootstrapSpec(tree); err != nil { return jb, err } - } else if err := validateNonBootstrapSpec(tree, jb, cfg.OCR().ObservationTimeout()); err != nil { + } else if err := validateNonBootstrapSpec(tree, jb, gcfg.OCR().ObservationTimeout()); err != nil { return jb, err } - if err := validateTimingParameters(cfg.EVM(), cfg.EVM().OCR(), cfg.Insecure(), spec, cfg.OCR()); err != nil { + if err := validateTimingParameters(cfg.EVM(), cfg.EVM().OCR(), gcfg.Insecure(), spec, gcfg.OCR()); err != nil { return jb, err } return jb, nil diff --git a/core/services/ocr/validate_test.go b/core/services/ocr/validate_test.go index e55c5d1a484..6e68559d09d 100644 --- a/core/services/ocr/validate_test.go +++ b/core/services/ocr/validate_test.go @@ -373,7 +373,7 @@ answer1 [type=median index=0]; } }) - s, err := ocr.ValidatedOracleSpecTomlCfg(func(id *big.Int) (evmconfig.ChainScopedConfig, error) { + s, err := ocr.ValidatedOracleSpecTomlCfg(c, func(id *big.Int) (evmconfig.ChainScopedConfig, error) { return evmtest.NewChainScopedConfig(t, c), nil }, tc.toml) tc.assertion(t, s, err) diff --git a/core/services/ocr2/database_test.go b/core/services/ocr2/database_test.go index 486bf1fd708..6e4f8f5dd66 100644 --- a/core/services/ocr2/database_test.go +++ b/core/services/ocr2/database_test.go @@ -61,7 +61,7 @@ func Test_DB_ReadWriteState(t *testing.T) { configDigest := testhelpers.MakeConfigDigest(t) cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, sqlDB, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, sqlDB).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) spec := MustInsertOCROracleSpec(t, sqlDB, key.EIP55Address) lggr := logger.TestLogger(t) @@ -152,7 +152,7 @@ func Test_DB_ReadWriteConfig(t *testing.T) { OffchainConfig: []byte{0x03, 0x04}, } cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, sqlDB, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, sqlDB).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) spec := MustInsertOCROracleSpec(t, sqlDB, key.EIP55Address) lggr := logger.TestLogger(t) @@ -239,7 +239,7 @@ func Test_DB_PendingTransmissions(t *testing.T) { sqlDB := setupDB(t) cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, sqlDB, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, sqlDB).Eth() key, _ := cltest.MustInsertRandomKey(t, ethKeyStore) lggr := logger.TestLogger(t) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index a00ed195903..7a2ef532fd2 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -38,6 +38,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" @@ -107,7 +108,7 @@ func (e ErrRelayNotEnabled) Error() string { } type RelayGetter interface { - Get(id relay.ID) (loop.Relayer, error) + Get(id types.RelayID) (loop.Relayer, error) } type Delegate struct { db *sqlx.DB // legacy: prefer to use ds instead @@ -130,7 +131,7 @@ type Delegate struct { mailMon *mailbox.Monitor legacyChains legacyevm.LegacyChainContainer // legacy: use relayers instead - capabilitiesRegistry types.CapabilitiesRegistry + capabilitiesRegistry core.CapabilitiesRegistry } type DelegateConfig interface { @@ -185,7 +186,9 @@ type ocr2Config interface { ContractPollInterval() time.Duration ContractTransmitterTransmitTimeout() time.Duration DatabaseTimeout() time.Duration + DefaultTransactionQueueDepth() uint32 KeyBundleID() (string, error) + SimulateTransactions() bool TraceLogging() bool CaptureAutomationCustomTelemetry() bool } @@ -242,7 +245,7 @@ func NewDelegate( ethKs keystore.Eth, relayers RelayGetter, mailMon *mailbox.Monitor, - capabilitiesRegistry types.CapabilitiesRegistry, + capabilitiesRegistry core.CapabilitiesRegistry, ) *Delegate { return &Delegate{ db: db, @@ -278,7 +281,7 @@ func (d *Delegate) BeforeJobCreated(spec job.Job) { } func (d *Delegate) AfterJobCreated(spec job.Job) {} func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) error { +func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job) error { // If the job spec is malformed in any way, we report the error but return nil so that // the job deletion itself isn't blocked. @@ -294,14 +297,14 @@ func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) er return nil } // we only have clean to do for the EVM - if rid.Network == relay.EVM { - return d.cleanupEVM(ctx, jb, q, rid) + if rid.Network == types.NetworkEVM { + return d.cleanupEVM(ctx, jb, rid) } return nil } // cleanupEVM is a helper for clean up EVM specific state when a job is deleted -func (d *Delegate) cleanupEVM(ctx context.Context, jb job.Job, q pg.Queryer, relayID relay.ID) error { +func (d *Delegate) cleanupEVM(ctx context.Context, jb job.Job, relayID types.RelayID) error { // If UnregisterFilter returns an // error, that means it failed to remove a valid active filter from the db. We do abort the job deletion // in that case, since it should be easy for the user to retry and will avoid leaving the db in @@ -386,7 +389,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)} } - if rid.Network == relay.EVM { + if rid.Network == types.NetworkEVM { lggr = logger.Sugared(lggr.With("evmChainID", rid.ChainID)) chain, err2 := d.legacyChains.Get(rid.ChainID) @@ -399,6 +402,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi } } spec.RelayConfig["effectiveTransmitterID"] = effectiveTransmitterID + spec.RelayConfig.ApplyDefaultsOCR2(d.cfg.OCR2()) ocrDB := NewDB(d.db, spec.ID, 0, lggr, d.cfg.Database()) if d.peerWrapper == nil { @@ -536,8 +540,8 @@ func (d *Delegate) newServicesGenericPlugin( ocrDB *db, lc ocrtypes.LocalConfig, ocrLogger commontypes.Logger, - capabilitiesRegistry types.CapabilitiesRegistry, - keyValueStore types.KeyValueStore, + capabilitiesRegistry core.CapabilitiesRegistry, + keyValueStore core.KeyValueStore, ) (srvs []job.ServiceCtx, err error) { spec := jb.OCR2OracleSpec // NOTE: we don't need to validate this config, since that happens as part of creating the job. @@ -635,7 +639,7 @@ func (d *Delegate) newServicesGenericPlugin( return nil, fmt.Errorf("cannot dump plugin config to string before sending to plugin: %s", err) } - pluginConfig := types.ReportingPluginServiceConfig{ + pluginConfig := core.ReportingPluginServiceConfig{ PluginName: pCfg.PluginName, Command: command, ProviderType: pCfg.ProviderType, @@ -739,7 +743,7 @@ func (d *Delegate) newServicesMercury( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "mercury"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("mercury services: expected EVM relayer got %s", rid.Network) } relayer, err := d.RelayGetter.Get(rid) @@ -823,7 +827,7 @@ func (d *Delegate) newServicesLLO( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "streams"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("streams services: expected EVM relayer got %s", rid.Network) } relayer, err := d.RelayGetter.Get(rid) @@ -998,7 +1002,7 @@ func (d *Delegate) newServicesDKG( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "DKG"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("DKG services: expected EVM relayer got %s", rid.Network) } @@ -1068,7 +1072,7 @@ func (d *Delegate) newServicesOCR2VRF( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "VRF"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("VRF services: expected EVM relayer got %s", rid.Network) } chain, err2 := d.legacyChains.Get(rid.ChainID) @@ -1182,10 +1186,10 @@ func (d *Delegate) newServicesOCR2VRF( lggr.ErrorIf(d.jobORM.RecordError(jb.ID, msg), "unable to record error") }) dkgReportingPluginFactoryDecorator := func(wrapped ocrtypes.ReportingPluginFactory) ocrtypes.ReportingPluginFactory { - return promwrapper.NewPromFactory(wrapped, "DKG", string(relay.EVM), chain.ID()) + return promwrapper.NewPromFactory(wrapped, "DKG", string(types.NetworkEVM), chain.ID()) } vrfReportingPluginFactoryDecorator := func(wrapped ocrtypes.ReportingPluginFactory) ocrtypes.ReportingPluginFactory { - return promwrapper.NewPromFactory(wrapped, "OCR2VRF", string(relay.EVM), chain.ID()) + return promwrapper.NewPromFactory(wrapped, "OCR2VRF", string(types.NetworkEVM), chain.ID()) } noopMonitoringEndpoint := telemetry.NoopAgent{} oracles, err2 := ocr2vrf.NewOCR2VRF(ocr2vrf.DKGVRFArgs{ @@ -1286,7 +1290,7 @@ func (d *Delegate) newServicesOCR2Keepers21( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keeper2"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) } @@ -1437,7 +1441,7 @@ func (d *Delegate) newServicesOCR2Keepers20( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "keepers2.0"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %s", rid.Network) } chain, err2 := d.legacyChains.Get(rid.ChainID) @@ -1561,7 +1565,7 @@ func (d *Delegate) newServicesOCR2Functions( if err != nil { return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "functions"} } - if rid.Network != relay.EVM { + if rid.Network != types.NetworkEVM { return nil, fmt.Errorf("functions services: expected EVM relayer got %s", rid.Network) } chain, err := d.legacyChains.Get(rid.ChainID) diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index ea8693d48ce..bae1f5f3e78 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -27,6 +27,7 @@ import ( ) func TestGetEVMEffectiveTransmitterID(t *testing.T) { + ctx := testutils.Context(t) customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -39,8 +40,8 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }) }) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) + keyStore := cltest.NewKeyStore(t, db) + require.NoError(t, keyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) lggr := logger.TestLogger(t) txManager := txmmocks.NewMockEvmTxManager(t) diff --git a/core/services/ocr2/plugins/dkg/config/config_test.go b/core/services/ocr2/plugins/dkg/config/config_test.go index fe796a9ad6c..f8cc1265ee1 100644 --- a/core/services/ocr2/plugins/dkg/config/config_test.go +++ b/core/services/ocr2/plugins/dkg/config/config_test.go @@ -7,21 +7,21 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" ) func TestValidatePluginConfig(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) - cfg := configtest.NewGeneralConfig(t, nil) db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()) + kst := cltest.NewKeyStore(t, db) - dkgEncryptKey, err := kst.DKGEncrypt().Create() + dkgEncryptKey, err := kst.DKGEncrypt().Create(ctx) require.NoError(t, err) - dkgSignKey, err := kst.DKGSign().Create() + dkgSignKey, err := kst.DKGSign().Create(ctx) require.NoError(t, err) encryptKeyBytes, err := dkgEncryptKey.PublicKey.MarshalBinary() diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go index 72997e28699..b8ecfbaceb4 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ b/core/services/ocr2/plugins/dkg/persistence/db.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) var ( @@ -60,7 +59,7 @@ type shareDB struct { } // NewShareDB creates a new DKG share database. -func NewShareDB(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID *big.Int, chainType relay.Network) ocr2vrftypes.DKGSharePersistence { +func NewShareDB(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID *big.Int, chainType string) ocr2vrftypes.DKGSharePersistence { return &shareDB{ q: pg.NewQ(db, lggr, cfg), lggr: lggr, diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index 53a5ae26758..a3949ea70dc 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -10,19 +10,19 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/types" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-vrf/types/hash" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) func setup(t testing.TB) (ocr2vrftypes.DKGSharePersistence, *sqlx.DB) { db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - return NewShareDB(db, lggr, pgtest.NewQConfig(true), big.NewInt(1337), relay.EVM), db + return NewShareDB(db, lggr, pgtest.NewQConfig(true), big.NewInt(1337), types.NetworkEVM), db } func TestShareDB_WriteShareRecords(t *testing.T) { diff --git a/core/services/ocr2/plugins/dkg/plugin.go b/core/services/ocr2/plugins/dkg/plugin.go index 0310122655f..65216ac1115 100644 --- a/core/services/ocr2/plugins/dkg/plugin.go +++ b/core/services/ocr2/plugins/dkg/plugin.go @@ -22,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -38,7 +37,7 @@ func NewDKGServices( db *sqlx.DB, qConfig pg.QConfig, chainID *big.Int, - network relay.Network, + network string, ) ([]job.ServiceCtx, error) { var pluginConfig config.PluginConfig err := json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &pluginConfig) diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index ae9bf5f01cd..3f96b49cfe0 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -317,6 +317,7 @@ func StartNewNode( ocr2Keystore []byte, thresholdKeyShare string, ) *Node { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) @@ -371,9 +372,9 @@ func StartNewNode( var kb ocr2key.KeyBundle if ocr2Keystore != nil { - kb, err = app.GetKeyStore().OCR2().Import(ocr2Keystore, "testPassword") + kb, err = app.GetKeyStore().OCR2().Import(ctx, ocr2Keystore, "testPassword") } else { - kb, err = app.GetKeyStore().OCR2().Create("evm") + kb, err = app.GetKeyStore().OCR2().Create(ctx, "evm") } require.NoError(t, err) diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go index e6a429a5f73..22217b83660 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" ) -var _ types.PipelineRunnerService = (*PipelineRunnerAdapter)(nil) +var _ core.PipelineRunnerService = (*PipelineRunnerAdapter)(nil) type pipelineRunner interface { ExecuteAndInsertFinishedRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger, saveSuccessfulTaskRuns bool) (runID int64, results pipeline.TaskRunResults, err error) @@ -24,7 +24,7 @@ type PipelineRunnerAdapter struct { logger logger.Logger } -func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) (types.TaskResults, error) { +func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, vars core.Vars, options core.Options) (core.TaskResults, error) { s := pipeline.Spec{ DotDagSource: spec, CreatedAt: time.Now(), @@ -50,13 +50,13 @@ func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, var return nil, err } - taskResults := make([]types.TaskResult, len(trrs)) + taskResults := make([]core.TaskResult, len(trrs)) for i, trr := range trrs { - taskResults[i] = types.TaskResult{ + taskResults[i] = core.TaskResult{ ID: trr.ID.String(), Type: string(trr.Task.Type()), Index: int(trr.Task.OutputIndex()), - TaskValue: types.TaskValue{ + TaskValue: core.TaskValue{ Value: trr.Result.OutputDB(), Error: trr.Result.Error, IsTerminal: len(trr.Task.Outputs()) == 0, diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index 647aaf59056..0d6bc02e198 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -36,14 +36,16 @@ answer; ` func TestAdapter_Integration(t *testing.T) { + testutils.SkipShortDB(t) + ctx := testutils.Context(t) logger := logger.TestLogger(t) cfg := configtest.NewTestGeneralConfig(t) url := cfg.Database().URL() db, err := pg.NewConnection(url.String(), cfg.Database().Dialect(), cfg.Database()) require.NoError(t, err) - keystore := keystore.NewInMemory(db, utils.FastScryptParams, logger, cfg.Database()) - pipelineORM := pipeline.NewORM(db, logger, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + keystore := keystore.NewInMemory(db, utils.FastScryptParams, logger) + pipelineORM := pipeline.NewORM(db, logger, cfg.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) jobORM := job.NewORM(db, pipelineORM, bridgesORM, keystore, logger, cfg.Database()) pr := pipeline.NewRunner( @@ -58,7 +60,7 @@ func TestAdapter_Integration(t *testing.T) { http.DefaultClient, http.DefaultClient, ) - err = keystore.Unlock(cfg.Password().Keystore()) + err = keystore.Unlock(ctx, cfg.Password().Keystore()) require.NoError(t, err) jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), cfg.OCR2(), cfg.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) @@ -76,7 +78,7 @@ func TestAdapter_Integration(t *testing.T) { err = jobORM.CreateJob(&jb) require.NoError(t, err) pra := generic.NewPipelineRunnerAdapter(logger, jb, pr) - results, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) + results, err := pra.ExecuteRun(testutils.Context(t), spec, core.Vars{Vars: map[string]interface{}{"val": 1}}, core.Options{}) require.NoError(t, err) finalResult := results[0].Value.Val.(decimal.Decimal) @@ -108,7 +110,7 @@ func TestAdapter_AddsDefaultVars(t *testing.T) { jobID, externalJobID, name := int32(100), uuid.New(), null.StringFrom("job-name") pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name}, mpr) - _, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{}, types.Options{}) + _, err := pra.ExecuteRun(testutils.Context(t), spec, core.Vars{}, core.Options{}) require.NoError(t, err) gotName, err := mpr.vars.Get("jb.name") @@ -131,7 +133,7 @@ func TestPipelineRunnerAdapter_SetsVarsOnSpec(t *testing.T) { pra := generic.NewPipelineRunnerAdapter(logger, job.Job{ID: jobID, ExternalJobID: externalJobID, Name: name, Type: jobType}, mpr) maxDuration := 100 * time.Second - _, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{}, types.Options{MaxTaskDuration: maxDuration}) + _, err := pra.ExecuteRun(testutils.Context(t), spec, core.Vars{}, core.Options{MaxTaskDuration: maxDuration}) require.NoError(t, err) assert.Equal(t, jobID, mpr.spec.JobID) diff --git a/core/services/ocr2/plugins/generic/telemetry_adapter.go b/core/services/ocr2/plugins/generic/telemetry_adapter.go index a2ec6ba20cf..ea2206202ee 100644 --- a/core/services/ocr2/plugins/generic/telemetry_adapter.go +++ b/core/services/ocr2/plugins/generic/telemetry_adapter.go @@ -9,10 +9,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" ) -var _ types.TelemetryService = (*TelemetryAdapter)(nil) +var _ core.TelemetryService = (*TelemetryAdapter)(nil) type TelemetryAdapter struct { endpointGenerator telemetry.MonitoringEndpointGenerator diff --git a/core/services/ocr2/plugins/llo/helpers_test.go b/core/services/ocr2/plugins/llo/helpers_test.go index 654b524bab5..73f7fedc926 100644 --- a/core/services/ocr2/plugins/llo/helpers_test.go +++ b/core/services/ocr2/plugins/llo/helpers_test.go @@ -59,7 +59,7 @@ type request struct { } func (r request) TransmitterID() ocr2types.Account { - return ocr2types.Account(fmt.Sprintf("%x", r.pk)) + return ocr2types.Account(r.pk.String()) } type mercuryServer struct { @@ -114,7 +114,7 @@ func startMercuryServer(t *testing.T, srv *mercuryServer, pubKeys []ed25519.Publ t.Fatalf("[MAIN] failed to listen: %v", err) } serverURL = lis.Addr().String() - s := wsrpc.NewServer(wsrpc.Creds(srv.privKey, pubKeys)) + s := wsrpc.NewServer(wsrpc.WithCreds(srv.privKey, pubKeys)) // Register mercury implementation with the wsrpc server pb.RegisterMercuryServer(s, srv) diff --git a/core/services/ocr2/plugins/llo/integration_test.go b/core/services/ocr2/plugins/llo/integration_test.go index df77316e4dd..b6f752541f4 100644 --- a/core/services/ocr2/plugins/llo/integration_test.go +++ b/core/services/ocr2/plugins/llo/integration_test.go @@ -173,10 +173,10 @@ func TestIntegration_LLO(t *testing.T) { t.Logf("Expect report from oracle %s", o.OracleIdentity.TransmitAccount) seen[o.OracleIdentity.TransmitAccount] = make(map[llotypes.ChannelID]struct{}) } - for req := range reqs { if _, exists := seen[req.TransmitterID()]; !exists { // oracle already reported on all channels; discard + // if this test timeouts, check for expected transmitter ID continue } @@ -188,7 +188,7 @@ func TestIntegration_LLO(t *testing.T) { t.Fatalf("FAIL: expected payload %#v to contain 'report'", v) } - t.Logf("Got report from oracle %x with format: %d", req.pk, req.req.ReportFormat) + t.Logf("Got report from oracle %s with format: %d", req.pk, req.req.ReportFormat) var r datastreamsllo.Report @@ -199,7 +199,7 @@ func TestIntegration_LLO(t *testing.T) { r, err = (datastreamsllo.JSONReportCodec{}).Decode(report.([]byte)) require.NoError(t, err, "expected valid JSON") case uint32(llotypes.ReportFormatEVM): - t.Logf("Got report (EVM) from oracle %x: 0x%x", req.pk, report.([]byte)) + t.Logf("Got report (EVM) from oracle %s: 0x%x", req.pk, report.([]byte)) var err error r, err = (lloevm.ReportCodec{}).Decode(report.([]byte)) require.NoError(t, err, "expected valid EVM encoding") diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 43d709453b7..fbb51557eb1 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -103,7 +103,7 @@ func startMercuryServer(t *testing.T, srv *mercuryServer, pubKeys []ed25519.Publ t.Fatalf("[MAIN] failed to listen: %v", err) } serverURL = lis.Addr().String() - s := wsrpc.NewServer(wsrpc.Creds(srv.privKey, pubKeys)) + s := wsrpc.NewServer(wsrpc.WithCreds(srv.privKey, pubKeys)) // Register mercury implementation with the wsrpc server pb.RegisterMercuryServer(s, srv) diff --git a/core/services/ocr2/plugins/mercury/plugin_test.go b/core/services/ocr2/plugins/mercury/plugin_test.go index 131f51af4b4..1d3260fdb1f 100644 --- a/core/services/ocr2/plugins/mercury/plugin_test.go +++ b/core/services/ocr2/plugins/mercury/plugin_test.go @@ -27,7 +27,6 @@ import ( libocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/plugins" @@ -74,7 +73,7 @@ var ( ID: 7, ContractID: "phony", FeedID: ptr(common.BytesToHash([]byte{1, 2, 3})), - Relay: relay.EVM, + Relay: commontypes.NetworkEVM, ChainID: "1", }, PipelineSpec: &pipeline.Spec{}, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go index 8c8ea721d73..0e2f87d0821 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go index 5a815987a83..0e9badc2ac3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go index c7fd7982904..8fc55abc7e7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go @@ -101,6 +101,7 @@ func setupClient(t *testing.T) *client { } func TestV02_SingleFeedRequest(t *testing.T) { + t.Parallel() upkeepId := big.NewInt(123456789) tests := []struct { name string @@ -382,6 +383,7 @@ func TestV02_SingleFeedRequest(t *testing.T) { } func TestV02_DoMercuryRequestV02(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" tests := []struct { @@ -624,6 +626,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { } func TestV02_DoMercuryRequestV02_MultipleFeedsSuccess(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -665,6 +668,7 @@ func TestV02_DoMercuryRequestV02_MultipleFeedsSuccess(t *testing.T) { } func TestV02_DoMercuryRequestV02_Timeout(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -719,6 +723,7 @@ func TestV02_DoMercuryRequestV02_Timeout(t *testing.T) { } func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedPipelineError(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -766,6 +771,7 @@ func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedPipelineError(t *testing.T } func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedErrCode(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -813,6 +819,7 @@ func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedErrCode(t *testing.T) { } func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedPipelineErrorConvertedError(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go index 9c0e2aaa147..be99296d153 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go @@ -99,6 +99,7 @@ func setupClient(t *testing.T) *client { } func TestV03_DoMercuryRequestV03(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) tests := []struct { @@ -179,6 +180,7 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { } func TestV03_DoMercuryRequestV03_MultipleFeedsSuccess(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -230,6 +232,7 @@ func TestV03_DoMercuryRequestV03_MultipleFeedsSuccess(t *testing.T) { } func TestV03_DoMercuryRequestV03_Timeout(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -286,6 +289,7 @@ func TestV03_DoMercuryRequestV03_Timeout(t *testing.T) { } func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedPipelineError(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -342,6 +346,7 @@ func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedPipelineError(t *testing.T } func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedErrCode(t *testing.T) { + t.Parallel() upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" @@ -412,6 +417,7 @@ func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedErrCode(t *testing.T) { } func TestV03_MultiFeedRequest(t *testing.T) { + t.Parallel() upkeepId := big.NewInt(123456789) tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go index d6982e9dbdb..ab8e9f04940 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go index 0ef1fdd4038..c68e7094cca 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index ea752256232..1054c59dd1c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -112,6 +112,7 @@ func setupNode( p2pV2Bootstrappers []commontypes.BootstrapperLocator, mercury mercury.MercuryEndpointMock, ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} cfg, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -143,10 +144,10 @@ func setupNode( }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, backend, nodeKey, p2pKey) - kb, err := app.GetKeyStore().OCR2().Create(chaintype.EVM) + kb, err := app.GetKeyStore().OCR2().Create(ctx, chaintype.EVM) require.NoError(t, err) - err = app.Start(testutils.Context(t)) + err = app.Start(ctx) require.NoError(t, err) t.Cleanup(func() { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go index 827b5ae9836..278fe573439 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go index c0f85d67e06..d62a08f6a86 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go index f59d048febe..7dddf15a322 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 94c4c0bb8fc..ac2695dc632 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -312,7 +312,7 @@ func setupNodeOCR2( b.Commit() } - kb, err := app.GetKeyStore().OCR2().Create("evm") + kb, err := app.GetKeyStore().OCR2().Create(ctx, "evm") require.NoError(t, err) return &ocr2Node{ @@ -371,10 +371,10 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { node := setupNodeOCR2(t, uni.owner, ports[i], fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) sendingKeys = append(sendingKeys, node.sendingKeys) - dkgSignKey, err := node.app.GetKeyStore().DKGSign().Create() + dkgSignKey, err := node.app.GetKeyStore().DKGSign().Create(ctx) require.NoError(t, err) - dkgEncryptKey, err := node.app.GetKeyStore().DKGEncrypt().Create() + dkgEncryptKey, err := node.app.GetKeyStore().DKGEncrypt().Create(ctx) require.NoError(t, err) kbs = append(kbs, node.keybundle) diff --git a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go index 418cb276011..4e4b912c75b 100644 --- a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go +++ b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/threshold/mocks/decryptor.go b/core/services/ocr2/plugins/threshold/mocks/decryptor.go index 5496483c9dd..daabd6d7de9 100644 --- a/core/services/ocr2/plugins/threshold/mocks/decryptor.go +++ b/core/services/ocr2/plugins/threshold/mocks/decryptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/validate/config.go b/core/services/ocr2/validate/config.go index 0084a18308b..d22bd781d19 100644 --- a/core/services/ocr2/validate/config.go +++ b/core/services/ocr2/validate/config.go @@ -7,9 +7,9 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) // OCR2Config contains OCR2 configurations for a job. @@ -19,6 +19,8 @@ type OCR2Config interface { ContractPollInterval() time.Duration ContractTransmitterTransmitTimeout() time.Duration DatabaseTimeout() time.Duration + DefaultTransactionQueueDepth() uint32 + SimulateTransactions() bool TraceLogging() bool } @@ -49,7 +51,7 @@ func ToLocalConfig(ocr2Config OCR2Config, insConf InsecureConfig, spec job.OCR2O ContractTransmitterTransmitTimeout: ocr2Config.ContractTransmitterTransmitTimeout(), DatabaseTimeout: ocr2Config.DatabaseTimeout(), } - if spec.Relay == relay.Solana && env.MedianPlugin.Cmd.Get() != "" { + if spec.Relay == commontypes.NetworkSolana && env.MedianPlugin.Cmd.Get() != "" { // Work around for Solana Feeds configured with zero values to support LOOP Plugins. minOCR2MaxDurationQuery, err := getMinOCR2MaxDurationQuery() if err != nil { diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 19c8043f25b..59f7053de56 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -23,7 +23,6 @@ import ( mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -54,7 +53,7 @@ func ValidatedOracleSpecToml(ctx context.Context, config OCR2Config, insConf Ins if jb.Type != job.OffchainReporting2 { return jb, pkgerrors.Errorf("the only supported type is currently 'offchainreporting2', got %s", jb.Type) } - if _, ok := relay.SupportedRelays[spec.Relay]; !ok { + if _, ok := types.SupportedRelays[spec.Relay]; !ok { return jb, pkgerrors.Errorf("no such relay %v supported", spec.Relay) } if len(spec.P2PV2Bootstrappers) > 0 { diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index 9ed7cbea477..84f473088bb 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -19,12 +19,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type RelayGetter interface { - Get(relay.ID) (loop.Relayer, error) + Get(types.RelayID) (loop.Relayer, error) } // Delegate creates Bootstrap jobs @@ -102,6 +100,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] if spec.FeedID != nil { spec.RelayConfig["feedID"] = *spec.FeedID } + spec.RelayConfig.ApplyDefaultsOCR2(d.ocr2Cfg) ctxVals := loop.ContextValues{ JobID: jb.ID, @@ -190,6 +189,6 @@ func (d *Delegate) AfterJobCreated(spec job.Job) { func (d *Delegate) BeforeJobDeleted(spec job.Job) {} // OnDeleteJob satisfies the job.Delegate interface. -func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job, q pg.Queryer) error { +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } diff --git a/core/services/ocrcommon/data_source.go b/core/services/ocrcommon/data_source.go index f07cfc0ab7a..9ca111dea68 100644 --- a/core/services/ocrcommon/data_source.go +++ b/core/services/ocrcommon/data_source.go @@ -3,7 +3,6 @@ package ocrcommon import ( "context" "encoding/json" - errjoin "errors" "fmt" "math/big" "sync" @@ -294,31 +293,30 @@ func (ds *inMemoryDataSourceCache) updateCache(ctx context.Context) error { ds.mu.Lock() defer ds.mu.Unlock() - // check for any errors - _, latestTrrs, latestUpdateErr := ds.executeRun(ctx) - if latestTrrs.FinalResult(ds.lggr).HasErrors() { - latestUpdateErr = errjoin.Join(append(latestTrrs.FinalResult(ds.lggr).AllErrors, latestUpdateErr)...) - } - - if latestUpdateErr != nil { + _, latestTrrs, err := ds.executeRun(ctx) + if err != nil { previousUpdateErr := ds.latestUpdateErr - ds.latestUpdateErr = latestUpdateErr - // raise log severity + ds.latestUpdateErr = err + // warn log if previous cache update also errored if previousUpdateErr != nil { ds.lggr.Warnf("consecutive cache updates errored: previous err: %v new err: %v", previousUpdateErr, ds.latestUpdateErr) } - return errors.Wrapf(ds.latestUpdateErr, "error executing run for spec ID %v", ds.spec.ID) + + return errors.Wrapf(ds.latestUpdateErr, "error updating in memory data source cache for spec ID %v", ds.spec.ID) } - ds.latestTrrs = latestTrrs - ds.latestResult = ds.latestTrrs.FinalResult(ds.lggr) - value, err := ds.inMemoryDataSource.parse(ds.latestResult) + value, err := ds.inMemoryDataSource.parse(latestTrrs.FinalResult(ds.lggr)) if err != nil { - return errors.Wrapf(err, "invalid result") + ds.latestUpdateErr = errors.Wrapf(err, "invalid result") + return ds.latestUpdateErr } - // backup in case data source fails continuously and node gets rebooted + // update cache values + ds.latestTrrs = latestTrrs + ds.latestResult = ds.latestTrrs.FinalResult(ds.lggr) + ds.latestUpdateErr = nil + // backup in case data source fails continuously and node gets rebooted timePairBytes, err := json.Marshal(&ResultTimePair{Result: *serializablebig.New(value), Time: time.Now()}) if err != nil { return fmt.Errorf("failed to marshal result time pair, err: %w", err) @@ -341,7 +339,7 @@ func (ds *inMemoryDataSourceCache) get(ctx context.Context) (pipeline.FinalResul ds.mu.RUnlock() if err := ds.updateCache(ctx); err != nil { - ds.lggr.Warnf("failed to update cache err: %v, returning stale result now, err: %v", err) + ds.lggr.Warnf("failed to update cache, returning stale result now, err: %v", err) } ds.mu.RLock() @@ -357,15 +355,15 @@ func (ds *inMemoryDataSourceCache) Observe(ctx context.Context, timestamp ocr2ty timePairBytes, err := ds.kvStore.Get(ctx, dataSourceCacheKey) if err != nil { - return nil, fmt.Errorf("failed to get result time pair bytes, err: %w", err) + return nil, fmt.Errorf("in memory data source cache is empty and failed to get backup persisted value, err: %w", err) } - if err := json.Unmarshal(timePairBytes, &resTime); err != nil { - return nil, fmt.Errorf("failed to unmarshal result time pair bytes, err: %w", err) + if err = json.Unmarshal(timePairBytes, &resTime); err != nil { + return nil, fmt.Errorf("in memory data source cache is empty and failed to unmarshal backup persisted value, err: %w", err) } if time.Since(resTime.Time) >= ds.stalenessAlertThreshold { - ds.lggr.Errorf("cache hasn't been updated for over %v, latestUpdateErr is: %v", ds.stalenessAlertThreshold, ds.latestUpdateErr) + ds.lggr.Errorf("in memory data source cache is empty and the persisted value hasn't been updated for over %v, latestUpdateErr is: %v", ds.stalenessAlertThreshold, ds.latestUpdateErr) } return resTime.Result.ToInt(), nil } @@ -376,6 +374,13 @@ func (ds *inMemoryDataSourceCache) Observe(ctx context.Context, timestamp ocr2ty ConfigDigest: timestamp.ConfigDigest.Hex(), }) + // if last update was unsuccessful, check how much time passed since a successful update + if ds.latestUpdateErr != nil { + if time.Since(ds.latestTrrs.GetTaskRunResultsFinishedAt()) >= ds.stalenessAlertThreshold { + ds.lggr.Errorf("in memory cache is old and hasn't been updated for over %v, latestUpdateErr is: %v", ds.stalenessAlertThreshold, ds.latestUpdateErr) + } + + } return ds.parse(latestResult) } diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index f46b2af27c5..e87f211fd21 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -33,20 +33,18 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.Contains(t, pw.Start(testutils.Context(t)).Error(), "No P2P keys found in keystore. Peer wrapper will not be fully initialized") }) t.Run("with one p2p key and matching P2P.PeerID returns nil", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V2.Enabled = ptr(true) - }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - k, err := keyStore.P2P().Create() + ctx := testutils.Context(t) + keyStore := cltest.NewKeyStore(t, db) + k, err := keyStore.P2P().Create(ctx) require.NoError(t, err) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(k.PeerID()) @@ -58,13 +56,14 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) t.Run("with one p2p key and mismatching P2P.PeerID returns error", func(t *testing.T) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pkey.PeerID(peerID)) }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) - _, err := keyStore.P2P().Create() + _, err := keyStore.P2P().Create(ctx) require.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) @@ -73,15 +72,12 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) t.Run("with multiple p2p keys and valid P2P.PeerID returns nil", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} - }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - k2, err := keyStore.P2P().Create() + ctx := testutils.Context(t) + keyStore := cltest.NewKeyStore(t, db) + k2, err := keyStore.P2P().Create(ctx) require.NoError(t, err) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(k2.PeerID()) @@ -94,14 +90,15 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) t.Run("with multiple p2p keys and mismatching P2P.PeerID returns error", func(t *testing.T) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = ptr(p2pkey.PeerID(peerID)) }) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) - _, err := keyStore.P2P().Create() + _, err := keyStore.P2P().Create(ctx) require.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) @@ -112,15 +109,15 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { func Test_SingletonPeerWrapper_Close(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - k, err := keyStore.P2P().Create() + keyStore := cltest.NewKeyStore(t, db) + k, err := keyStore.P2P().Create(ctx) require.NoError(t, err) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.P2P.V2.Enabled = ptr(true) c.P2P.PeerID = ptr(k.PeerID()) c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(100 * time.Millisecond) diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index 6d85aa857a4..52ffb31cea0 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -2,15 +2,16 @@ package ocrcommon import ( "context" + "time" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) type Runner interface { - InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error + InsertFinishedRun(ctx context.Context, ds sqlutil.DataSource, run *pipeline.Run, saveSuccessfulTaskRuns bool) error } type RunResultSaver struct { @@ -19,7 +20,7 @@ type RunResultSaver struct { maxSuccessfulRuns uint64 runResults chan *pipeline.Run pipelineRunner Runner - done chan struct{} + stopCh services.StopChan logger logger.Logger } @@ -36,7 +37,7 @@ func NewResultRunSaver(pipelineRunner Runner, maxSuccessfulRuns: maxSuccessfulRuns, runResults: make(chan *pipeline.Run, resultsWriteDepth), pipelineRunner: pipelineRunner, - done: make(chan struct{}), + stopCh: make(chan struct{}), logger: logger.Named("RunResultSaver"), } } @@ -55,6 +56,8 @@ func (r *RunResultSaver) Save(run *pipeline.Run) { func (r *RunResultSaver) Start(context.Context) error { return r.StartOnce("RunResultSaver", func() error { go func() { + ctx, cancel := r.stopCh.NewCtx() + defer cancel() for { select { case run := <-r.runResults: @@ -66,10 +69,10 @@ func (r *RunResultSaver) Start(context.Context) error { r.logger.Tracew("RunSaver: saving job run", "run", run) // We do not want save successful TaskRuns as OCR runs very frequently so a lot of records // are produced and the successful TaskRuns do not provide value. - if err := r.pipelineRunner.InsertFinishedRun(run, false); err != nil { + if err := r.pipelineRunner.InsertFinishedRun(ctx, nil, run, false); err != nil { r.logger.Errorw("error inserting finished results", "err", err) } - case <-r.done: + case <-r.stopCh: return } } @@ -80,7 +83,10 @@ func (r *RunResultSaver) Start(context.Context) error { func (r *RunResultSaver) Close() error { return r.StopOnce("RunResultSaver", func() error { - r.done <- struct{}{} + close(r.stopCh) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() // In the unlikely event that there are remaining runResults to write, // drain the channel and save them. @@ -88,7 +94,7 @@ func (r *RunResultSaver) Close() error { select { case run := <-r.runResults: r.logger.Infow("RunSaver: saving job run before exiting", "run", run) - if err := r.pipelineRunner.InsertFinishedRun(run, false); err != nil { + if err := r.pipelineRunner.InsertFinishedRun(ctx, nil, run, false); err != nil { r.logger.Errorw("error inserting finished results", "err", err) } default: diff --git a/core/services/ocrcommon/run_saver_test.go b/core/services/ocrcommon/run_saver_test.go index 7bfe60f2a06..a965792ca1f 100644 --- a/core/services/ocrcommon/run_saver_test.go +++ b/core/services/ocrcommon/run_saver_test.go @@ -25,7 +25,7 @@ func TestRunSaver(t *testing.T) { pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = int64(d) + args.Get(2).(*pipeline.Run).ID = int64(d) }). Once() rs.Save(&pipeline.Run{ID: int64(i)}) diff --git a/core/services/ocrcommon/transmitter_test.go b/core/services/ocrcommon/transmitter_test.go index c56896ab2b9..d6a07190800 100644 --- a/core/services/ocrcommon/transmitter_test.go +++ b/core/services/ocrcommon/transmitter_test.go @@ -13,7 +13,6 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/services/ocrcommon" ) @@ -26,8 +25,7 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -67,8 +65,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -119,8 +116,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() fromAddress := common.Address{} @@ -150,8 +146,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/services/p2p/types/mocks/peer.go b/core/services/p2p/types/mocks/peer.go index 23824b99a44..3a2e218c170 100644 --- a/core/services/p2p/types/mocks/peer.go +++ b/core/services/p2p/types/mocks/peer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/p2p/types/mocks/peer_wrapper.go b/core/services/p2p/types/mocks/peer_wrapper.go index 02347cf6b86..cd20dc7ad94 100644 --- a/core/services/p2p/types/mocks/peer_wrapper.go +++ b/core/services/p2p/types/mocks/peer_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/p2p/types/mocks/signer.go b/core/services/p2p/types/mocks/signer.go index 274116be57c..baacbef07bd 100644 --- a/core/services/p2p/types/mocks/signer.go +++ b/core/services/p2p/types/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/p2p/wrapper/wrapper.go b/core/services/p2p/wrapper/wrapper.go index fd47c6c2dd2..acb6694b5a3 100644 --- a/core/services/p2p/wrapper/wrapper.go +++ b/core/services/p2p/wrapper/wrapper.go @@ -66,7 +66,9 @@ func convertPeerConfig(keystoreP2P keystore.P2P, p2pConfig config.P2P) (p2p.Peer DeltaDial: p2pConfig.V2().DeltaDial().Duration(), DiscovererDatabase: discovererDB, - MetricsRegisterer: prometheus.DefaultRegisterer, + // NOTE: this is equivalent to prometheus.DefaultRegisterer, but we need to use a separate + // object to avoid conflicts with the OCR registerer + MetricsRegisterer: prometheus.NewRegistry(), } return peerConfig, nil diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go index a88b2165a2e..a0fc28c6862 100644 --- a/core/services/pipeline/common.go +++ b/core/services/pipeline/common.go @@ -217,6 +217,17 @@ func (result *TaskRunResult) IsTerminal() bool { // TaskRunResults represents a collection of results for all task runs for one pipeline run type TaskRunResults []TaskRunResult +// GetTaskRunResultsFinishedAt returns latest finishedAt time from TaskRunResults. +func (trrs TaskRunResults) GetTaskRunResultsFinishedAt() time.Time { + var finishedTime time.Time + for _, trr := range trrs { + if trr.FinishedAt.Valid && trr.FinishedAt.Time.After(finishedTime) { + finishedTime = trr.FinishedAt.Time + } + } + return finishedTime +} + // FinalResult pulls the FinalResult for the pipeline_run from the task runs // It needs to respect the output index of each task func (trrs TaskRunResults) FinalResult(l logger.Logger) FinalResult { diff --git a/core/services/pipeline/helpers_test.go b/core/services/pipeline/helpers_test.go index 9ee2dc693f2..0bbdef7a7f2 100644 --- a/core/services/pipeline/helpers_test.go +++ b/core/services/pipeline/helpers_test.go @@ -5,6 +5,7 @@ import ( "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ) @@ -63,3 +64,5 @@ func (t *ETHTxTask) HelperSetDependencies(legacyChains legacyevm.LegacyChainCont t.specGasLimit = specGasLimit t.jobType = jobType } + +func (o *orm) Prune(ds sqlutil.DataSource, pipelineSpecID int32) { o.prune(ds, pipelineSpecID) } diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index b29a3cc9e11..1c9213443fa 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/orm.go b/core/services/pipeline/mocks/orm.go index b06041767a1..2fa6d8681e8 100644 --- a/core/services/pipeline/mocks/orm.go +++ b/core/services/pipeline/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -8,10 +8,10 @@ import ( models "github.com/smartcontractkit/chainlink/v2/core/store/models" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + time "time" uuid "github.com/google/uuid" @@ -40,24 +40,17 @@ func (_m *ORM) Close() error { return r0 } -// CreateRun provides a mock function with given fields: run, qopts -func (_m *ORM) CreateRun(run *pipeline.Run, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CreateRun provides a mock function with given fields: ctx, run +func (_m *ORM) CreateRun(ctx context.Context, run *pipeline.Run) error { + ret := _m.Called(ctx, run) if len(ret) == 0 { panic("no return value specified for CreateRun") } var r0 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) error); ok { - r0 = rf(run, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run) error); ok { + r0 = rf(ctx, run) } else { r0 = ret.Error(0) } @@ -65,16 +58,9 @@ func (_m *ORM) CreateRun(run *pipeline.Run, qopts ...pg.QOpt) error { return r0 } -// CreateSpec provides a mock function with given fields: _a0, maxTaskTimeout, qopts -func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, qopts ...pg.QOpt) (int32, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, _a0, maxTaskTimeout) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CreateSpec provides a mock function with given fields: ctx, ds, _a2, maxTaskTimeout +func (_m *ORM) CreateSpec(ctx context.Context, ds pipeline.CreateDataSource, _a2 pipeline.Pipeline, maxTaskTimeout models.Interval) (int32, error) { + ret := _m.Called(ctx, ds, _a2, maxTaskTimeout) if len(ret) == 0 { panic("no return value specified for CreateSpec") @@ -82,17 +68,17 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, var r0 int32 var r1 error - if rf, ok := ret.Get(0).(func(pipeline.Pipeline, models.Interval, ...pg.QOpt) (int32, error)); ok { - return rf(_a0, maxTaskTimeout, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, pipeline.CreateDataSource, pipeline.Pipeline, models.Interval) (int32, error)); ok { + return rf(ctx, ds, _a2, maxTaskTimeout) } - if rf, ok := ret.Get(0).(func(pipeline.Pipeline, models.Interval, ...pg.QOpt) int32); ok { - r0 = rf(_a0, maxTaskTimeout, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, pipeline.CreateDataSource, pipeline.Pipeline, models.Interval) int32); ok { + r0 = rf(ctx, ds, _a2, maxTaskTimeout) } else { r0 = ret.Get(0).(int32) } - if rf, ok := ret.Get(1).(func(pipeline.Pipeline, models.Interval, ...pg.QOpt) error); ok { - r1 = rf(_a0, maxTaskTimeout, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, pipeline.CreateDataSource, pipeline.Pipeline, models.Interval) error); ok { + r1 = rf(ctx, ds, _a2, maxTaskTimeout) } else { r1 = ret.Error(1) } @@ -100,17 +86,37 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, return r0, r1 } -// DeleteRun provides a mock function with given fields: id -func (_m *ORM) DeleteRun(id int64) error { - ret := _m.Called(id) +// DataSource provides a mock function with given fields: +func (_m *ORM) DataSource() sqlutil.DataSource { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DataSource") + } + + var r0 sqlutil.DataSource + if rf, ok := ret.Get(0).(func() sqlutil.DataSource); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(sqlutil.DataSource) + } + } + + return r0 +} + +// DeleteRun provides a mock function with given fields: ctx, id +func (_m *ORM) DeleteRun(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for DeleteRun") } var r0 error - if rf, ok := ret.Get(0).(func(int64) error); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) } else { r0 = ret.Error(0) } @@ -136,9 +142,9 @@ func (_m *ORM) DeleteRunsOlderThan(_a0 context.Context, _a1 time.Duration) error return r0 } -// FindRun provides a mock function with given fields: id -func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { - ret := _m.Called(id) +// FindRun provides a mock function with given fields: ctx, id +func (_m *ORM) FindRun(ctx context.Context, id int64) (pipeline.Run, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for FindRun") @@ -146,17 +152,17 @@ func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { var r0 pipeline.Run var r1 error - if rf, ok := ret.Get(0).(func(int64) (pipeline.Run, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, int64) (pipeline.Run, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(int64) pipeline.Run); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, int64) pipeline.Run); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(pipeline.Run) } - if rf, ok := ret.Get(1).(func(int64) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -164,9 +170,9 @@ func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { return r0, r1 } -// GetAllRuns provides a mock function with given fields: -func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { - ret := _m.Called() +// GetAllRuns provides a mock function with given fields: ctx +func (_m *ORM) GetAllRuns(ctx context.Context) ([]pipeline.Run, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetAllRuns") @@ -174,19 +180,19 @@ func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { var r0 []pipeline.Run var r1 error - if rf, ok := ret.Get(0).(func() ([]pipeline.Run, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) ([]pipeline.Run, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() []pipeline.Run); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) []pipeline.Run); ok { + r0 = rf(ctx) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]pipeline.Run) } } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -194,24 +200,6 @@ func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { return r0, r1 } -// GetQ provides a mock function with given fields: -func (_m *ORM) GetQ() pg.Q { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetQ") - } - - var r0 pg.Q - if rf, ok := ret.Get(0).(func() pg.Q); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(pg.Q) - } - - return r0 -} - // GetUnfinishedRuns provides a mock function with given fields: _a0, _a1, _a2 func (_m *ORM) GetUnfinishedRuns(_a0 context.Context, _a1 time.Time, _a2 func(pipeline.Run) error) error { ret := _m.Called(_a0, _a1, _a2) @@ -250,24 +238,17 @@ func (_m *ORM) HealthReport() map[string]error { return r0 } -// InsertFinishedRun provides a mock function with given fields: run, saveSuccessfulTaskRuns, qopts -func (_m *ORM) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run, saveSuccessfulTaskRuns) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertFinishedRun provides a mock function with given fields: ctx, run, saveSuccessfulTaskRuns +func (_m *ORM) InsertFinishedRun(ctx context.Context, run *pipeline.Run, saveSuccessfulTaskRuns bool) error { + ret := _m.Called(ctx, run, saveSuccessfulTaskRuns) if len(ret) == 0 { panic("no return value specified for InsertFinishedRun") } var r0 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, bool, ...pg.QOpt) error); ok { - r0 = rf(run, saveSuccessfulTaskRuns, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, bool) error); ok { + r0 = rf(ctx, run, saveSuccessfulTaskRuns) } else { r0 = ret.Error(0) } @@ -275,24 +256,17 @@ func (_m *ORM) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, return r0 } -// InsertFinishedRunWithSpec provides a mock function with given fields: run, saveSuccessfulTaskRuns, qopts -func (_m *ORM) InsertFinishedRunWithSpec(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run, saveSuccessfulTaskRuns) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertFinishedRunWithSpec provides a mock function with given fields: ctx, run, saveSuccessfulTaskRuns +func (_m *ORM) InsertFinishedRunWithSpec(ctx context.Context, run *pipeline.Run, saveSuccessfulTaskRuns bool) error { + ret := _m.Called(ctx, run, saveSuccessfulTaskRuns) if len(ret) == 0 { panic("no return value specified for InsertFinishedRunWithSpec") } var r0 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, bool, ...pg.QOpt) error); ok { - r0 = rf(run, saveSuccessfulTaskRuns, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, bool) error); ok { + r0 = rf(ctx, run, saveSuccessfulTaskRuns) } else { r0 = ret.Error(0) } @@ -300,24 +274,17 @@ func (_m *ORM) InsertFinishedRunWithSpec(run *pipeline.Run, saveSuccessfulTaskRu return r0 } -// InsertFinishedRuns provides a mock function with given fields: run, saveSuccessfulTaskRuns, qopts -func (_m *ORM) InsertFinishedRuns(run []*pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run, saveSuccessfulTaskRuns) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertFinishedRuns provides a mock function with given fields: ctx, run, saveSuccessfulTaskRuns +func (_m *ORM) InsertFinishedRuns(ctx context.Context, run []*pipeline.Run, saveSuccessfulTaskRuns bool) error { + ret := _m.Called(ctx, run, saveSuccessfulTaskRuns) if len(ret) == 0 { panic("no return value specified for InsertFinishedRuns") } var r0 error - if rf, ok := ret.Get(0).(func([]*pipeline.Run, bool, ...pg.QOpt) error); ok { - r0 = rf(run, saveSuccessfulTaskRuns, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, []*pipeline.Run, bool) error); ok { + r0 = rf(ctx, run, saveSuccessfulTaskRuns) } else { r0 = ret.Error(0) } @@ -325,24 +292,17 @@ func (_m *ORM) InsertFinishedRuns(run []*pipeline.Run, saveSuccessfulTaskRuns bo return r0 } -// InsertRun provides a mock function with given fields: run, qopts -func (_m *ORM) InsertRun(run *pipeline.Run, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertRun provides a mock function with given fields: ctx, run +func (_m *ORM) InsertRun(ctx context.Context, run *pipeline.Run) error { + ret := _m.Called(ctx, run) if len(ret) == 0 { panic("no return value specified for InsertRun") } var r0 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) error); ok { - r0 = rf(run, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run) error); ok { + r0 = rf(ctx, run) } else { r0 = ret.Error(0) } @@ -404,16 +364,9 @@ func (_m *ORM) Start(_a0 context.Context) error { return r0 } -// StoreRun provides a mock function with given fields: run, qopts -func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// StoreRun provides a mock function with given fields: ctx, run +func (_m *ORM) StoreRun(ctx context.Context, run *pipeline.Run) (bool, error) { + ret := _m.Called(ctx, run) if len(ret) == 0 { panic("no return value specified for StoreRun") @@ -421,17 +374,17 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { var r0 bool var r1 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) (bool, error)); ok { - return rf(run, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run) (bool, error)); ok { + return rf(ctx, run) } - if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) bool); ok { - r0 = rf(run, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run) bool); ok { + r0 = rf(ctx, run) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(*pipeline.Run, ...pg.QOpt) error); ok { - r1 = rf(run, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, *pipeline.Run) error); ok { + r1 = rf(ctx, run) } else { r1 = ret.Error(1) } @@ -439,9 +392,27 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { return r0, r1 } -// UpdateTaskRunResult provides a mock function with given fields: taskID, result -func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pipeline.Run, bool, error) { - ret := _m.Called(taskID, result) +// Transact provides a mock function with given fields: _a0, _a1 +func (_m *ORM) Transact(_a0 context.Context, _a1 func(pipeline.ORM) error) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Transact") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, func(pipeline.ORM) error) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateTaskRunResult provides a mock function with given fields: ctx, taskID, result +func (_m *ORM) UpdateTaskRunResult(ctx context.Context, taskID uuid.UUID, result pipeline.Result) (pipeline.Run, bool, error) { + ret := _m.Called(ctx, taskID, result) if len(ret) == 0 { panic("no return value specified for UpdateTaskRunResult") @@ -450,23 +421,23 @@ func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pi var r0 pipeline.Run var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(uuid.UUID, pipeline.Result) (pipeline.Run, bool, error)); ok { - return rf(taskID, result) + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, pipeline.Result) (pipeline.Run, bool, error)); ok { + return rf(ctx, taskID, result) } - if rf, ok := ret.Get(0).(func(uuid.UUID, pipeline.Result) pipeline.Run); ok { - r0 = rf(taskID, result) + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, pipeline.Result) pipeline.Run); ok { + r0 = rf(ctx, taskID, result) } else { r0 = ret.Get(0).(pipeline.Run) } - if rf, ok := ret.Get(1).(func(uuid.UUID, pipeline.Result) bool); ok { - r1 = rf(taskID, result) + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID, pipeline.Result) bool); ok { + r1 = rf(ctx, taskID, result) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(uuid.UUID, pipeline.Result) error); ok { - r2 = rf(taskID, result) + if rf, ok := ret.Get(2).(func(context.Context, uuid.UUID, pipeline.Result) error); ok { + r2 = rf(ctx, taskID, result) } else { r2 = ret.Error(2) } @@ -474,6 +445,26 @@ func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pi return r0, r1, r2 } +// WithDataSource provides a mock function with given fields: _a0 +func (_m *ORM) WithDataSource(_a0 sqlutil.DataSource) pipeline.ORM { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WithDataSource") + } + + var r0 pipeline.ORM + if rf, ok := ret.Get(0).(func(sqlutil.DataSource) pipeline.ORM); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(pipeline.ORM) + } + } + + return r0 +} + // NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewORM(t interface { diff --git a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go index 40f2ba4dd32..dcc15bf6fc2 100644 --- a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go +++ b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/runner.go b/core/services/pipeline/mocks/runner.go index 3de2703f0c7..88d71c76c3a 100644 --- a/core/services/pipeline/mocks/runner.go +++ b/core/services/pipeline/mocks/runner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -8,10 +8,10 @@ import ( logger "github.com/smartcontractkit/chainlink/v2/core/logger" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + uuid "github.com/google/uuid" ) @@ -164,24 +164,17 @@ func (_m *Runner) InitializePipeline(spec pipeline.Spec) (*pipeline.Pipeline, er return r0, r1 } -// InsertFinishedRun provides a mock function with given fields: run, saveSuccessfulTaskRuns, qopts -func (_m *Runner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, run, saveSuccessfulTaskRuns) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertFinishedRun provides a mock function with given fields: ctx, ds, run, saveSuccessfulTaskRuns +func (_m *Runner) InsertFinishedRun(ctx context.Context, ds sqlutil.DataSource, run *pipeline.Run, saveSuccessfulTaskRuns bool) error { + ret := _m.Called(ctx, ds, run, saveSuccessfulTaskRuns) if len(ret) == 0 { panic("no return value specified for InsertFinishedRun") } var r0 error - if rf, ok := ret.Get(0).(func(*pipeline.Run, bool, ...pg.QOpt) error); ok { - r0 = rf(run, saveSuccessfulTaskRuns, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, sqlutil.DataSource, *pipeline.Run, bool) error); ok { + r0 = rf(ctx, ds, run, saveSuccessfulTaskRuns) } else { r0 = ret.Error(0) } @@ -189,24 +182,17 @@ func (_m *Runner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bo return r0 } -// InsertFinishedRuns provides a mock function with given fields: runs, saveSuccessfulTaskRuns, qopts -func (_m *Runner) InsertFinishedRuns(runs []*pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, runs, saveSuccessfulTaskRuns) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// InsertFinishedRuns provides a mock function with given fields: ctx, ds, runs, saveSuccessfulTaskRuns +func (_m *Runner) InsertFinishedRuns(ctx context.Context, ds sqlutil.DataSource, runs []*pipeline.Run, saveSuccessfulTaskRuns bool) error { + ret := _m.Called(ctx, ds, runs, saveSuccessfulTaskRuns) if len(ret) == 0 { panic("no return value specified for InsertFinishedRuns") } var r0 error - if rf, ok := ret.Get(0).(func([]*pipeline.Run, bool, ...pg.QOpt) error); ok { - r0 = rf(runs, saveSuccessfulTaskRuns, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, sqlutil.DataSource, []*pipeline.Run, bool) error); ok { + r0 = rf(ctx, ds, runs, saveSuccessfulTaskRuns) } else { r0 = ret.Error(0) } @@ -255,17 +241,17 @@ func (_m *Runner) Ready() error { return r0 } -// ResumeRun provides a mock function with given fields: taskID, value, err -func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error { - ret := _m.Called(taskID, value, err) +// ResumeRun provides a mock function with given fields: ctx, taskID, value, err +func (_m *Runner) ResumeRun(ctx context.Context, taskID uuid.UUID, value interface{}, err error) error { + ret := _m.Called(ctx, taskID, value, err) if len(ret) == 0 { panic("no return value specified for ResumeRun") } var r0 error - if rf, ok := ret.Get(0).(func(uuid.UUID, interface{}, error) error); ok { - r0 = rf(taskID, value, err) + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, interface{}, error) error); ok { + r0 = rf(ctx, taskID, value, err) } else { r0 = ret.Error(0) } @@ -274,7 +260,7 @@ func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) erro } // Run provides a mock function with given fields: ctx, run, l, saveSuccessfulTaskRuns, fn -func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(pg.Queryer) error) (bool, error) { +func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(sqlutil.DataSource) error) (bool, error) { ret := _m.Called(ctx, run, l, saveSuccessfulTaskRuns, fn) if len(ret) == 0 { @@ -283,16 +269,16 @@ func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, s var r0 bool var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(pg.Queryer) error) (bool, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(sqlutil.DataSource) error) (bool, error)); ok { return rf(ctx, run, l, saveSuccessfulTaskRuns, fn) } - if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(pg.Queryer) error) bool); ok { + if rf, ok := ret.Get(0).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(sqlutil.DataSource) error) bool); ok { r0 = rf(ctx, run, l, saveSuccessfulTaskRuns, fn) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(pg.Queryer) error) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *pipeline.Run, logger.Logger, bool, func(sqlutil.DataSource) error) error); ok { r1 = rf(ctx, run, l, saveSuccessfulTaskRuns, fn) } else { r1 = ret.Error(1) diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index c32693e4db4..3bebfb8cbad 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -14,6 +14,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -71,33 +72,42 @@ const KeepersObservationSource = ` encode_check_upkeep_tx -> check_upkeep_tx -> decode_check_upkeep_tx -> calculate_perform_data_len -> perform_data_lessthan_limit -> check_perform_data_limit -> encode_perform_upkeep_tx -> simulate_perform_upkeep_tx -> decode_check_perform_tx -> check_success -> perform_upkeep_tx ` +type CreateDataSource interface { + GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error +} + //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore type ORM interface { services.Service - CreateSpec(pipeline Pipeline, maxTaskTimeout models.Interval, qopts ...pg.QOpt) (int32, error) - CreateRun(run *Run, qopts ...pg.QOpt) (err error) - InsertRun(run *Run, qopts ...pg.QOpt) error - DeleteRun(id int64) error - StoreRun(run *Run, qopts ...pg.QOpt) (restart bool, err error) - UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, start bool, err error) - InsertFinishedRun(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) (err error) - InsertFinishedRunWithSpec(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) (err error) + + // ds is optional and to be removed after completing https://smartcontract-it.atlassian.net/browse/BCF-2978 + CreateSpec(ctx context.Context, ds CreateDataSource, pipeline Pipeline, maxTaskTimeout models.Interval) (int32, error) + CreateRun(ctx context.Context, run *Run) (err error) + InsertRun(ctx context.Context, run *Run) error + DeleteRun(ctx context.Context, id int64) error + StoreRun(ctx context.Context, run *Run) (restart bool, err error) + UpdateTaskRunResult(ctx context.Context, taskID uuid.UUID, result Result) (run Run, start bool, err error) + InsertFinishedRun(ctx context.Context, run *Run, saveSuccessfulTaskRuns bool) (err error) + InsertFinishedRunWithSpec(ctx context.Context, run *Run, saveSuccessfulTaskRuns bool) (err error) // InsertFinishedRuns inserts all the given runs into the database. // If saveSuccessfulTaskRuns is false, only errored runs are saved. - InsertFinishedRuns(run []*Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) (err error) + InsertFinishedRuns(ctx context.Context, run []*Run, saveSuccessfulTaskRuns bool) (err error) DeleteRunsOlderThan(context.Context, time.Duration) error - FindRun(id int64) (Run, error) - GetAllRuns() ([]Run, error) + FindRun(ctx context.Context, id int64) (Run, error) + GetAllRuns(ctx context.Context) ([]Run, error) GetUnfinishedRuns(context.Context, time.Time, func(run Run) error) error - GetQ() pg.Q + + DataSource() sqlutil.DataSource + WithDataSource(sqlutil.DataSource) ORM + Transact(context.Context, func(ORM) error) error } type orm struct { services.StateMachine - q pg.Q + ds sqlutil.DataSource lggr logger.Logger maxSuccessfulRuns uint64 // jobID => count @@ -109,17 +119,14 @@ type orm struct { var _ ORM = (*orm)(nil) -func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, jobPipelineMaxSuccessfulRuns uint64) *orm { +func NewORM(ds sqlutil.DataSource, lggr logger.Logger, jobPipelineMaxSuccessfulRuns uint64) *orm { ctx, cancel := context.WithCancel(context.Background()) return &orm{ - services.StateMachine{}, - pg.NewQ(db, lggr, cfg), - lggr.Named("PipelineORM"), - jobPipelineMaxSuccessfulRuns, - sync.Map{}, - sync.WaitGroup{}, - ctx, - cancel, + ds: ds, + lggr: lggr.Named("PipelineORM"), + maxSuccessfulRuns: jobPipelineMaxSuccessfulRuns, + ctx: ctx, + cncl: cancel, } } @@ -152,23 +159,56 @@ func (o *orm) HealthReport() map[string]error { return map[string]error{o.Name(): o.Healthy()} } -func (o *orm) CreateSpec(pipeline Pipeline, maxTaskDuration models.Interval, qopts ...pg.QOpt) (id int32, err error) { - q := o.q.WithOpts(qopts...) +func (o *orm) Transact(ctx context.Context, fn func(ORM) error) error { + return sqlutil.Transact(ctx, func(tx sqlutil.DataSource) ORM { + return o.withDataSource(tx) + }, o.ds, nil, func(tx ORM) error { + defer func() { + if err := tx.Close(); err != nil { + o.lggr.Warnw("Error closing temporary transactional ORM", "err", err) + } + }() + return fn(tx) + }) +} + +func (o *orm) DataSource() sqlutil.DataSource { return o.ds } + +func (o *orm) WithDataSource(ds sqlutil.DataSource) ORM { return o.withDataSource(ds) } + +func (o *orm) withDataSource(ds sqlutil.DataSource) *orm { + ctx, cancel := context.WithCancel(context.Background()) + return &orm{ + ds: ds, + lggr: o.lggr, + maxSuccessfulRuns: o.maxSuccessfulRuns, + ctx: ctx, + cncl: cancel, + } +} + +func (o *orm) transact(ctx context.Context, fn func(*orm) error) error { + return sqlutil.Transact(ctx, o.withDataSource, o.ds, nil, fn) +} + +func (o *orm) CreateSpec(ctx context.Context, ds CreateDataSource, pipeline Pipeline, maxTaskDuration models.Interval) (id int32, err error) { sql := `INSERT INTO pipeline_specs (dot_dag_source, max_task_duration, created_at) VALUES ($1, $2, NOW()) RETURNING id;` - err = q.Get(&id, sql, pipeline.Source, maxTaskDuration) + if ds == nil { + ds = o.ds + } + err = ds.GetContext(ctx, &id, sql, pipeline.Source, maxTaskDuration) return id, errors.WithStack(err) } -func (o *orm) CreateRun(run *Run, qopts ...pg.QOpt) (err error) { +func (o *orm) CreateRun(ctx context.Context, run *Run) (err error) { if run.CreatedAt.IsZero() { return errors.New("run.CreatedAt must be set") } - q := o.q.WithOpts(qopts...) - err = q.Transaction(func(tx pg.Queryer) error { - if e := o.InsertRun(run, pg.WithQueryer(tx)); e != nil { + err = o.transact(ctx, func(tx *orm) error { + if e := tx.InsertRun(ctx, run); e != nil { return errors.Wrap(e, "error inserting pipeline_run") } @@ -182,10 +222,9 @@ func (o *orm) CreateRun(run *Run, qopts ...pg.QOpt) (err error) { run.PipelineTaskRuns[i].PipelineRunID = run.ID } - sql := ` - INSERT INTO pipeline_task_runs (pipeline_run_id, id, type, index, output, error, dot_id, created_at) + sql := `INSERT INTO pipeline_task_runs (pipeline_run_id, id, type, index, output, error, dot_id, created_at) VALUES (:pipeline_run_id, :id, :type, :index, :output, :error, :dot_id, :created_at);` - _, err = tx.NamedExec(sql, run.PipelineTaskRuns) + _, err = tx.ds.NamedExecContext(ctx, sql, run.PipelineTaskRuns) return err }) @@ -193,33 +232,34 @@ func (o *orm) CreateRun(run *Run, qopts ...pg.QOpt) (err error) { } // InsertRun inserts a run into the database -func (o *orm) InsertRun(run *Run, qopts ...pg.QOpt) error { +func (o *orm) InsertRun(ctx context.Context, run *Run) error { if run.Status() == RunStatusCompleted { - defer o.Prune(o.q, run.PruningKey) + defer o.prune(o.ds, run.PruningKey) } - q := o.q.WithOpts(qopts...) - sql := `INSERT INTO pipeline_runs (pipeline_spec_id, pruning_key, meta, all_errors, fatal_errors, inputs, outputs, created_at, finished_at, state) + query, args, err := o.ds.BindNamed(`INSERT INTO pipeline_runs (pipeline_spec_id, pruning_key, meta, all_errors, fatal_errors, inputs, outputs, created_at, finished_at, state) VALUES (:pipeline_spec_id, :pruning_key, :meta, :all_errors, :fatal_errors, :inputs, :outputs, :created_at, :finished_at, :state) - RETURNING *;` - return q.GetNamed(sql, run, run) + RETURNING *;`, run) + if err != nil { + return fmt.Errorf("error binding arg: %w", err) + } + return o.ds.GetContext(ctx, run, query, args...) } // StoreRun will persist a partially executed run before suspending, or finish a run. // If `restart` is true, then new task run data is available and the run should be resumed immediately. -func (o *orm) StoreRun(run *Run, qopts ...pg.QOpt) (restart bool, err error) { - q := o.q.WithOpts(qopts...) - err = q.Transaction(func(tx pg.Queryer) error { +func (o *orm) StoreRun(ctx context.Context, run *Run) (restart bool, err error) { + err = o.transact(ctx, func(tx *orm) error { finished := run.FinishedAt.Valid if !finished { // Lock the current run. This prevents races with /v2/resume sql := `SELECT id FROM pipeline_runs WHERE id = $1 FOR UPDATE;` - if _, err = tx.Exec(sql, run.ID); err != nil { + if _, err = tx.ds.ExecContext(ctx, sql, run.ID); err != nil { return errors.Wrap(err, "StoreRun") } taskRuns := []TaskRun{} // Reload task runs, we want to check for any changes while the run was ongoing - if err = sqlx.Select(tx, &taskRuns, `SELECT * FROM pipeline_task_runs WHERE pipeline_run_id = $1`, run.ID); err != nil { + if err = tx.ds.SelectContext(ctx, &taskRuns, `SELECT * FROM pipeline_task_runs WHERE pipeline_run_id = $1`, run.ID); err != nil { return errors.Wrap(err, "StoreRun") } @@ -246,17 +286,17 @@ func (o *orm) StoreRun(run *Run, qopts ...pg.QOpt) (restart bool, err error) { // Suspend the run run.State = RunStatusSuspended - if _, err = sqlx.NamedExec(tx, `UPDATE pipeline_runs SET state = :state WHERE id = :id`, run); err != nil { + if _, err = tx.ds.NamedExecContext(ctx, `UPDATE pipeline_runs SET state = :state WHERE id = :id`, run); err != nil { return errors.Wrap(err, "StoreRun") } } else { - defer o.Prune(tx, run.PruningKey) + defer o.prune(tx.ds, run.PruningKey) // Simply finish the run, no need to do any sort of locking if run.Outputs.Val == nil || len(run.FatalErrors)+len(run.AllErrors) == 0 { return errors.Errorf("run must have both Outputs and Errors, got Outputs: %#v, FatalErrors: %#v, AllErrors: %#v", run.Outputs.Val, run.FatalErrors, run.AllErrors) } sql := `UPDATE pipeline_runs SET state = :state, finished_at = :finished_at, all_errors= :all_errors, fatal_errors= :fatal_errors, outputs = :outputs WHERE id = :id` - if _, err = sqlx.NamedExec(tx, sql, run); err != nil { + if _, err = tx.ds.NamedExecContext(ctx, sql, run); err != nil { return errors.Wrap(err, "StoreRun") } } @@ -272,7 +312,7 @@ func (o *orm) StoreRun(run *Run, qopts ...pg.QOpt) (restart bool, err error) { // NOTE: can't use Select() to auto scan because we're using NamedQuery, // sqlx.Named + Select is possible but it's about the same amount of code var rows *sqlx.Rows - rows, err = sqlx.NamedQuery(tx, sql, run.PipelineTaskRuns) + rows, err = sqlx.NamedQueryContext(ctx, tx.ds, sql, run.PipelineTaskRuns) if err != nil { return errors.Wrap(err, "StoreRun") } @@ -288,17 +328,17 @@ func (o *orm) StoreRun(run *Run, qopts ...pg.QOpt) (restart bool, err error) { } // DeleteRun cleans up a run that failed and is marked failEarly (should leave no trace of the run) -func (o *orm) DeleteRun(id int64) error { +func (o *orm) DeleteRun(ctx context.Context, id int64) error { // NOTE: this will cascade and wipe pipeline_task_runs too - _, err := o.q.Exec(`DELETE FROM pipeline_runs WHERE id = $1`, id) + _, err := o.ds.ExecContext(ctx, `DELETE FROM pipeline_runs WHERE id = $1`, id) return err } -func (o *orm) UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, start bool, err error) { +func (o *orm) UpdateTaskRunResult(ctx context.Context, taskID uuid.UUID, result Result) (run Run, start bool, err error) { if result.OutputDB().Valid && result.ErrorDB().Valid { panic("run result must specify either output or error, not both") } - err = o.q.Transaction(func(tx pg.Queryer) error { + err = o.transact(ctx, func(tx *orm) error { sql := ` SELECT pipeline_runs.*, pipeline_specs.dot_dag_source "pipeline_spec.dot_dag_source", job_pipeline_specs.job_id "job_id" FROM pipeline_runs @@ -307,13 +347,13 @@ func (o *orm) UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, sta JOIN job_pipeline_specs ON (job_pipeline_specs.pipeline_spec_id = pipeline_specs.id) WHERE pipeline_task_runs.id = $1 AND pipeline_runs.state in ('running', 'suspended') FOR UPDATE` - if err = tx.Get(&run, sql, taskID); err != nil { + if err = tx.ds.GetContext(ctx, &run, sql, taskID); err != nil { return fmt.Errorf("failed to find pipeline run for task ID %s: %w", taskID.String(), err) } // Update the task with result sql = `UPDATE pipeline_task_runs SET output = $2, error = $3, finished_at = $4 WHERE id = $1` - if _, err = tx.Exec(sql, taskID, result.OutputDB(), result.ErrorDB(), time.Now()); err != nil { + if _, err = tx.ds.ExecContext(ctx, sql, taskID, result.OutputDB(), result.ErrorDB(), time.Now()); err != nil { return fmt.Errorf("failed to update pipeline task run: %w", err) } @@ -322,21 +362,20 @@ func (o *orm) UpdateTaskRunResult(taskID uuid.UUID, result Result) (run Run, sta run.State = RunStatusRunning sql = `UPDATE pipeline_runs SET state = $2 WHERE id = $1` - if _, err = tx.Exec(sql, run.ID, run.State); err != nil { + if _, err = tx.ds.ExecContext(ctx, sql, run.ID, run.State); err != nil { return fmt.Errorf("failed to update pipeline run state: %w", err) } } - return loadAssociations(tx, []*Run{&run}) + return loadAssociations(ctx, tx.ds, []*Run{&run}) }) return run, start, err } // InsertFinishedRuns inserts all the given runs into the database. -func (o *orm) InsertFinishedRuns(runs []*Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.Transaction(func(tx pg.Queryer) error { +func (o *orm) InsertFinishedRuns(ctx context.Context, runs []*Run, saveSuccessfulTaskRuns bool) error { + err := o.transact(ctx, func(tx *orm) error { pipelineRunsQuery := ` INSERT INTO pipeline_runs (pipeline_spec_id, pruning_key, meta, all_errors, fatal_errors, inputs, outputs, created_at, finished_at, state) @@ -344,7 +383,7 @@ VALUES (:pipeline_spec_id, :pruning_key, :meta, :all_errors, :fatal_errors, :inputs, :outputs, :created_at, :finished_at, :state) RETURNING id ` - rows, errQ := tx.NamedQuery(pipelineRunsQuery, runs) + rows, errQ := sqlx.NamedQueryContext(ctx, tx.ds, pipelineRunsQuery, runs) if errQ != nil { return errors.Wrap(errQ, "inserting finished pipeline runs") } @@ -369,7 +408,7 @@ RETURNING id defer func() { for pruningKey := range pruningKeysm { - o.Prune(tx, pruningKey) + o.prune(tx.ds, pruningKey) } }() @@ -385,7 +424,7 @@ VALUES (:pipeline_run_id, :id, :type, :index, :output, :error, :dot_id, :created pipelineTaskRuns = append(pipelineTaskRuns, run.PipelineTaskRuns...) } - _, errE := tx.NamedExec(pipelineTaskRunsQuery, pipelineTaskRuns) + _, errE := tx.ds.NamedExecContext(ctx, pipelineTaskRunsQuery, pipelineTaskRuns) return errors.Wrap(errE, "insert pipeline task runs") }) return errors.Wrap(err, "InsertFinishedRuns failed") @@ -411,7 +450,7 @@ func (o *orm) checkFinishedRun(run *Run, saveSuccessfulTaskRuns bool) error { // If saveSuccessfulTaskRuns = false, we only save errored runs. // That way if the job is run frequently (such as OCR) we avoid saving a large number of successful task runs // which do not provide much value. -func (o *orm) InsertFinishedRun(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) (err error) { +func (o *orm) InsertFinishedRun(ctx context.Context, run *Run, saveSuccessfulTaskRuns bool) (err error) { if err = o.checkFinishedRun(run, saveSuccessfulTaskRuns); err != nil { return err } @@ -421,13 +460,12 @@ func (o *orm) InsertFinishedRun(run *Run, saveSuccessfulTaskRuns bool, qopts ... return nil } - q := o.q.WithOpts(qopts...) - err = q.Transaction(o.insertFinishedRunTx(run, saveSuccessfulTaskRuns)) + err = o.insertFinishedRun(ctx, run, saveSuccessfulTaskRuns) return errors.Wrap(err, "InsertFinishedRun failed") } // InsertFinishedRunWithSpec works like InsertFinishedRun but also inserts the pipeline spec. -func (o *orm) InsertFinishedRunWithSpec(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) (err error) { +func (o *orm) InsertFinishedRunWithSpec(ctx context.Context, run *Run, saveSuccessfulTaskRuns bool) (err error) { if err = o.checkFinishedRun(run, saveSuccessfulTaskRuns); err != nil { return err } @@ -437,57 +475,55 @@ func (o *orm) InsertFinishedRunWithSpec(run *Run, saveSuccessfulTaskRuns bool, q return nil } - q := o.q.WithOpts(qopts...) - err = q.Transaction(func(tx pg.Queryer) error { + err = o.transact(ctx, func(tx *orm) error { sqlStmt1 := `INSERT INTO pipeline_specs (dot_dag_source, max_task_duration, created_at) VALUES ($1, $2, NOW()) RETURNING id;` - err = tx.Get(&run.PipelineSpecID, sqlStmt1, run.PipelineSpec.DotDagSource, run.PipelineSpec.MaxTaskDuration) + err = tx.ds.GetContext(ctx, &run.PipelineSpecID, sqlStmt1, run.PipelineSpec.DotDagSource, run.PipelineSpec.MaxTaskDuration) if err != nil { return errors.Wrap(err, "failed to insert pipeline_specs") } // This `job_pipeline_specs` record won't be primary since when this method is called, the job already exists, so it will have primary record. sqlStmt2 := `INSERT INTO job_pipeline_specs (job_id, pipeline_spec_id, is_primary) VALUES ($1, $2, false)` - _, err = tx.Exec(sqlStmt2, run.JobID, run.PipelineSpecID) + _, err = tx.ds.ExecContext(ctx, sqlStmt2, run.JobID, run.PipelineSpecID) if err != nil { return errors.Wrap(err, "failed to insert job_pipeline_specs") } - return o.insertFinishedRunTx(run, saveSuccessfulTaskRuns)(tx) + return tx.insertFinishedRun(ctx, run, saveSuccessfulTaskRuns) }) return errors.Wrap(err, "InsertFinishedRun failed") } -func (o *orm) insertFinishedRunTx(run *Run, saveSuccessfulTaskRuns bool) func(tx pg.Queryer) error { - return func(tx pg.Queryer) error { - sql := `INSERT INTO pipeline_runs (pipeline_spec_id, pruning_key, meta, all_errors, fatal_errors, inputs, outputs, created_at, finished_at, state) +func (o *orm) insertFinishedRun(ctx context.Context, run *Run, saveSuccessfulTaskRuns bool) error { + sql := `INSERT INTO pipeline_runs (pipeline_spec_id, pruning_key, meta, all_errors, fatal_errors, inputs, outputs, created_at, finished_at, state) VALUES (:pipeline_spec_id, :pruning_key, :meta, :all_errors, :fatal_errors, :inputs, :outputs, :created_at, :finished_at, :state) RETURNING id;` - query, args, e := tx.BindNamed(sql, run) - if e != nil { - return errors.Wrap(e, "failed to bind") - } + query, args, err := o.ds.BindNamed(sql, run) + if err != nil { + return errors.Wrap(err, "failed to bind") + } - if err := tx.QueryRowx(query, args...).Scan(&run.ID); err != nil { - return errors.Wrap(err, "error inserting finished pipeline_run") - } + if err = o.ds.QueryRowxContext(ctx, query, args...).Scan(&run.ID); err != nil { + return errors.Wrap(err, "error inserting finished pipeline_run") + } - // update the ID key everywhere - for i := range run.PipelineTaskRuns { - run.PipelineTaskRuns[i].PipelineRunID = run.ID - } + // update the ID key everywhere + for i := range run.PipelineTaskRuns { + run.PipelineTaskRuns[i].PipelineRunID = run.ID + } - if !saveSuccessfulTaskRuns && !run.HasErrors() { - return nil - } + if !saveSuccessfulTaskRuns && !run.HasErrors() { + return nil + } - defer o.Prune(tx, run.PruningKey) - sql = ` + defer o.prune(o.ds, run.PruningKey) + sql = ` INSERT INTO pipeline_task_runs (pipeline_run_id, id, type, index, output, error, dot_id, created_at, finished_at) VALUES (:pipeline_run_id, :id, :type, :index, :output, :error, :dot_id, :created_at, :finished_at);` - _, err := tx.NamedExec(sql, run.PipelineTaskRuns) - return errors.Wrap(err, "failed to insert pipeline_task_runs") - } + _, err = o.ds.NamedExecContext(ctx, sql, run.PipelineTaskRuns) + return errors.Wrap(err, "failed to insert pipeline_task_runs") + } // DeleteRunsOlderThan deletes all pipeline_runs that have been finished for a certain threshold to free DB space @@ -495,14 +531,12 @@ func (o *orm) insertFinishedRunTx(run *Run, saveSuccessfulTaskRuns bool) func(tx func (o *orm) DeleteRunsOlderThan(ctx context.Context, threshold time.Duration) error { start := time.Now() - q := o.q.WithOpts(pg.WithParentCtxInheritTimeout(ctx)) - queryThreshold := start.Add(-threshold) rowsDeleted := int64(0) err := pg.Batch(func(_, limit uint) (count uint, err error) { - result, cancel, err := q.ExecQIter(` + result, err := o.ds.ExecContext(ctx, ` WITH batched_pipeline_runs AS ( SELECT * FROM pipeline_runs WHERE finished_at < ($1) @@ -515,7 +549,6 @@ WHERE pipeline_runs.id = batched_pipeline_runs.id`, queryThreshold, limit, ) - defer cancel() if err != nil { return count, errors.Wrap(err, "DeleteRunsOlderThan failed to delete old pipeline_runs") } @@ -539,7 +572,7 @@ WHERE pipeline_runs.id = batched_pipeline_runs.id`, o.lggr.Debugw("pipeline_runs reaper VACUUM ANALYZE query completed", "duration", time.Since(start)) }(deleteTS) - err = q.ExecQ("VACUUM ANALYZE pipeline_runs") + _, err = o.ds.ExecContext(ctx, "VACUUM ANALYZE pipeline_runs") if err != nil { o.lggr.Warnw("DeleteRunsOlderThan successfully deleted old pipeline_runs rows, but failed to run VACUUM ANALYZE", "err", err) return nil @@ -548,13 +581,13 @@ WHERE pipeline_runs.id = batched_pipeline_runs.id`, return nil } -func (o *orm) FindRun(id int64) (r Run, err error) { +func (o *orm) FindRun(ctx context.Context, id int64) (r Run, err error) { var runs []*Run - err = o.q.Transaction(func(tx pg.Queryer) error { - if err = tx.Select(&runs, `SELECT * from pipeline_runs WHERE id = $1 LIMIT 1`, id); err != nil { + err = o.transact(ctx, func(tx *orm) error { + if err = tx.ds.SelectContext(ctx, &runs, `SELECT * from pipeline_runs WHERE id = $1 LIMIT 1`, id); err != nil { return errors.Wrap(err, "failed to load runs") } - return loadAssociations(tx, runs) + return loadAssociations(ctx, tx.ds, runs) }) if len(runs) == 0 { return r, sql.ErrNoRows @@ -562,15 +595,15 @@ func (o *orm) FindRun(id int64) (r Run, err error) { return *runs[0], err } -func (o *orm) GetAllRuns() (runs []Run, err error) { +func (o *orm) GetAllRuns(ctx context.Context) (runs []Run, err error) { var runsPtrs []*Run - err = o.q.Transaction(func(tx pg.Queryer) error { - err = tx.Select(&runsPtrs, `SELECT * from pipeline_runs ORDER BY created_at ASC, id ASC`) + err = o.transact(ctx, func(tx *orm) error { + err = tx.ds.SelectContext(ctx, &runsPtrs, `SELECT * from pipeline_runs ORDER BY created_at ASC, id ASC`) if err != nil { return errors.Wrap(err, "failed to load runs") } - return loadAssociations(tx, runsPtrs) + return loadAssociations(ctx, tx.ds, runsPtrs) }) runs = make([]Run, len(runsPtrs)) for i, runPtr := range runsPtrs { @@ -580,17 +613,16 @@ func (o *orm) GetAllRuns() (runs []Run, err error) { } func (o *orm) GetUnfinishedRuns(ctx context.Context, now time.Time, fn func(run Run) error) error { - q := o.q.WithOpts(pg.WithParentCtx(ctx)) return pg.Batch(func(offset, limit uint) (count uint, err error) { var runs []*Run - err = q.Transaction(func(tx pg.Queryer) error { - err = tx.Select(&runs, `SELECT * from pipeline_runs WHERE state = $1 AND created_at < $2 ORDER BY created_at ASC, id ASC OFFSET $3 LIMIT $4`, RunStatusRunning, now, offset, limit) + err = o.transact(ctx, func(tx *orm) error { + err = tx.ds.SelectContext(ctx, &runs, `SELECT * from pipeline_runs WHERE state = $1 AND created_at < $2 ORDER BY created_at ASC, id ASC OFFSET $3 LIMIT $4`, RunStatusRunning, now, offset, limit) if err != nil { return errors.Wrap(err, "failed to load runs") } - err = loadAssociations(tx, runs) + err = loadAssociations(ctx, tx.ds, runs) if err != nil { return err } @@ -608,7 +640,7 @@ func (o *orm) GetUnfinishedRuns(ctx context.Context, now time.Time, fn func(run } // loads PipelineSpec and PipelineTaskRuns for Runs in exactly 2 queries -func loadAssociations(q pg.Queryer, runs []*Run) error { +func loadAssociations(ctx context.Context, ds sqlutil.DataSource, runs []*Run) error { if len(runs) == 0 { return nil } @@ -635,7 +667,7 @@ func loadAssociations(q pg.Queryer, runs []*Run) error { LEFT JOIN job_pipeline_specs jps ON jps.pipeline_spec_id=ps.id LEFT JOIN jobs ON jobs.id=jps.job_id WHERE ps.id = ANY($1)` - if err := q.Select(&specs, sqlQuery, pipelineSpecIDs); err != nil { + if err := ds.SelectContext(ctx, &specs, sqlQuery, pipelineSpecIDs); err != nil { return errors.Wrap(err, "failed to postload pipeline_specs for runs") } for _, spec := range specs { @@ -647,7 +679,7 @@ func loadAssociations(q pg.Queryer, runs []*Run) error { var taskRuns []TaskRun taskRunPRIDM := make(map[int64][]TaskRun, len(runs)) // keyed by pipelineRunID - if err := q.Select(&taskRuns, `SELECT * FROM pipeline_task_runs WHERE pipeline_run_id = ANY($1) ORDER BY created_at ASC, id ASC`, pipelineRunIDs); err != nil { + if err := ds.SelectContext(ctx, &taskRuns, `SELECT * FROM pipeline_task_runs WHERE pipeline_run_id = ANY($1) ORDER BY created_at ASC, id ASC`, pipelineRunIDs); err != nil { return errors.Wrap(err, "failed to postload pipeline_task_runs for runs") } for _, taskRun := range taskRuns { @@ -662,10 +694,6 @@ func loadAssociations(q pg.Queryer, runs []*Run) error { return nil } -func (o *orm) GetQ() pg.Q { - return o.q -} - func (o *orm) loadCount(jobID int32) *atomic.Uint64 { // fast path; avoids allocation actual, exists := o.pm.Load(jobID) @@ -681,7 +709,7 @@ func (o *orm) loadCount(jobID int32) *atomic.Uint64 { // this value or higher const syncLimit = 1000 -// Prune attempts to keep the pipeline_runs table capped close to the +// prune attempts to keep the pipeline_runs table capped close to the // maxSuccessfulRuns length for each job_id. // // It does this synchronously for small values and async/sampled for large @@ -689,13 +717,13 @@ const syncLimit = 1000 // // Note this does not guarantee the pipeline_runs table is kept to exactly the // max length, rather that it doesn't excessively larger than it. -func (o *orm) Prune(tx pg.Queryer, jobID int32) { +func (o *orm) prune(ds sqlutil.DataSource, jobID int32) { if jobID == 0 { o.lggr.Panic("expected a non-zero job ID") } // For small maxSuccessfulRuns its fast enough to prune every time if o.maxSuccessfulRuns < syncLimit { - o.execPrune(tx, jobID) + o.execPrune(o.ctx, ds, jobID) return } // for large maxSuccessfulRuns we do it async on a sampled basis @@ -708,9 +736,11 @@ func (o *orm) Prune(tx pg.Queryer, jobID int32) { go func() { o.lggr.Debugw("Pruning runs", "jobID", jobID, "count", val, "every", every, "maxSuccessfulRuns", o.maxSuccessfulRuns) defer o.wg.Done() - // Must not use tx here since it's async and the transaction + // Must not use ds here since it's async and the transaction // could be stale - o.execPrune(o.q.WithOpts(pg.WithLongQueryTimeout()), jobID) + ctx, cancel := context.WithTimeout(sqlutil.WithoutDefaultTimeout(o.ctx), time.Minute) + defer cancel() + o.execPrune(ctx, o.ds, jobID) }() }) if !ok { @@ -720,8 +750,8 @@ func (o *orm) Prune(tx pg.Queryer, jobID int32) { } } -func (o *orm) execPrune(q pg.Queryer, jobID int32) { - res, err := q.ExecContext(o.ctx, `DELETE FROM pipeline_runs WHERE pruning_key = $1 AND state = $2 AND id NOT IN ( +func (o *orm) execPrune(ctx context.Context, ds sqlutil.DataSource, jobID int32) { + res, err := ds.ExecContext(o.ctx, `DELETE FROM pipeline_runs WHERE pruning_key = $1 AND state = $2 AND id NOT IN ( SELECT id FROM pipeline_runs WHERE pruning_key = $1 AND state = $2 ORDER BY id DESC @@ -739,7 +769,7 @@ LIMIT $3 if rowsAffected == 0 { // check the spec still exists and garbage collect if necessary var exists bool - if err := q.GetContext(o.ctx, &exists, `SELECT EXISTS(SELECT ps.* FROM pipeline_specs ps JOIN job_pipeline_specs jps ON (ps.id=jps.pipeline_spec_id) WHERE jps.job_id = $1)`, jobID); err != nil { + if err := ds.GetContext(ctx, &exists, `SELECT EXISTS(SELECT ps.* FROM pipeline_specs ps JOIN job_pipeline_specs jps ON (ps.id=jps.pipeline_spec_id) WHERE jps.job_id = $1)`, jobID); err != nil { o.lggr.Errorw("Failed check existence of pipeline_spec while pruning runs", "err", err, "jobID", jobID) return } diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index e5bf319f056..bba928534ba 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -71,10 +71,10 @@ func setupORM(t *testing.T, heavy bool) (db *sqlx.DB, orm pipeline.ORM, jorm job db = pgtest.NewSqlxDB(t) } cfg := ormconfig{pgtest.NewQConfig(true)} - orm = pipeline.NewORM(db, logger.TestLogger(t), cfg, cfg.JobPipelineMaxSuccessfulRuns()) + orm = pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipelineMaxSuccessfulRuns()) config := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) + keyStore := cltest.NewKeyStore(t, db) bridgeORM := bridges.NewORM(db) jorm = job.NewORM(db, orm, bridgeORM, keyStore, lggr, config.Database()) @@ -91,6 +91,7 @@ func setupLiteORM(t *testing.T) (db *sqlx.DB, orm pipeline.ORM, jorm job.ORM) { } func Test_PipelineORM_CreateSpec(t *testing.T) { + ctx := testutils.Context(t) db, orm, _ := setupLiteORM(t) var ( @@ -102,7 +103,7 @@ func Test_PipelineORM_CreateSpec(t *testing.T) { Source: source, } - id, err := orm.CreateSpec(p, maxTaskDuration) + id, err := orm.CreateSpec(ctx, nil, p, maxTaskDuration) require.NoError(t, err) actual := pipeline.Spec{} @@ -121,7 +122,8 @@ func Test_PipelineORM_FindRun(t *testing.T) { require.NoError(t, err) expected := mustInsertPipelineRun(t, orm) - run, err := orm.FindRun(expected.ID) + ctx := testutils.Context(t) + run, err := orm.FindRun(ctx, expected.ID) require.NoError(t, err) require.Equal(t, expected.ID, run.ID) @@ -138,12 +140,14 @@ func mustInsertPipelineRun(t *testing.T, orm pipeline.ORM) pipeline.Run { FinishedAt: null.Time{}, } - require.NoError(t, orm.InsertRun(&run)) + ctx := testutils.Context(t) + require.NoError(t, orm.InsertRun(ctx, &run)) return run } func mustInsertAsyncRun(t *testing.T, orm pipeline.ORM, jobORM job.ORM) *pipeline.Run { t.Helper() + ctx := testutils.Context(t) s := ` ds1 [type=bridge async=true name="example-bridge" timeout=0 requestData=<{"data": {"coin": "BTC", "market": "USD"}}>] @@ -178,12 +182,13 @@ answer2 [type=bridge name=election_winner index=1]; CreatedAt: time.Now(), } - err = orm.CreateRun(run) + err = orm.CreateRun(ctx, run) require.NoError(t, err) return run } func TestInsertFinishedRuns(t *testing.T) { + ctx := testutils.Context(t) db, orm, _ := setupLiteORM(t) _, err := db.Exec(`SET CONSTRAINTS fk_pipeline_runs_pruning_key DEFERRED`) @@ -207,7 +212,7 @@ func TestInsertFinishedRuns(t *testing.T) { Outputs: jsonserializable.JSONSerializable{}, } - require.NoError(t, orm.InsertRun(&r)) + require.NoError(t, orm.InsertRun(ctx, &r)) r.PipelineTaskRuns = []pipeline.TaskRun{ { @@ -238,12 +243,13 @@ func TestInsertFinishedRuns(t *testing.T) { runs = append(runs, &r) } - err = orm.InsertFinishedRuns(runs, true) + err = orm.InsertFinishedRuns(ctx, runs, true) require.NoError(t, err) } func Test_PipelineORM_InsertFinishedRunWithSpec(t *testing.T) { + ctx := testutils.Context(t) db, orm, jorm := setupLiteORM(t) s := ` @@ -314,7 +320,7 @@ answer2 [type=bridge name=election_winner index=1]; run.AllErrors = append(run.AllErrors, null.NewString("", false)) run.State = pipeline.RunStatusCompleted - err = orm.InsertFinishedRunWithSpec(run, true) + err = orm.InsertFinishedRunWithSpec(ctx, run, true) require.NoError(t, err) var pipelineSpec pipeline.Spec @@ -330,6 +336,7 @@ answer2 [type=bridge name=election_winner index=1]; // Tests that inserting run results, then later updating the run results via upsert will work correctly. func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { + ctx := testutils.Context(t) _, orm, jorm := setupLiteORM(t) run := mustInsertAsyncRun(t, orm, jorm) @@ -357,14 +364,14 @@ func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { FinishedAt: null.TimeFrom(now), }, } - restart, err := orm.StoreRun(run) + restart, err := orm.StoreRun(ctx, run) require.NoError(t, err) // no new data, so we don't need a restart require.Equal(t, false, restart) // the run is paused require.Equal(t, pipeline.RunStatusSuspended, run.State) - r, err := orm.FindRun(run.ID) + r, err := orm.FindRun(ctx, run.ID) require.NoError(t, err) run = &r // this is an incomplete run, so partial results should be present (regardless of saveSuccessfulTaskRuns) @@ -388,14 +395,14 @@ func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { FinishedAt: null.TimeFrom(now), }, } - restart, err = orm.StoreRun(run) + restart, err = orm.StoreRun(ctx, run) require.NoError(t, err) // no new data, so we don't need a restart require.Equal(t, false, restart) // the run is paused require.Equal(t, pipeline.RunStatusSuspended, run.State) - r, err = orm.FindRun(run.ID) + r, err = orm.FindRun(ctx, run.ID) require.NoError(t, err) run = &r // this is an incomplete run, so partial results should be present (regardless of saveSuccessfulTaskRuns) @@ -409,11 +416,12 @@ func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { // Tests that trying to persist a partial run while new data became available (i.e. via /v2/restart) // will detect a restart and update the result data on the Run. func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { + ctx := testutils.Context(t) db, orm, jorm := setupLiteORM(t) run := mustInsertAsyncRun(t, orm, jorm) - r, err := orm.FindRun(run.ID) + r, err := orm.FindRun(ctx, run.ID) require.NoError(t, err) require.Equal(t, run.Inputs, r.Inputs) @@ -459,7 +467,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { }, } - restart, err := orm.StoreRun(run) + restart, err := orm.StoreRun(ctx, run) require.NoError(t, err) // new data available! immediately restart the run require.Equal(t, true, restart) @@ -474,6 +482,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { } func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { + ctx := testutils.Context(t) _, orm, jorm := setupLiteORM(t) run := mustInsertAsyncRun(t, orm, jorm) @@ -525,13 +534,13 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { require.Equal(t, pipeline.RunStatusRunning, run.State) // Now store a partial run - restart, err := orm.StoreRun(run) + restart, err := orm.StoreRun(ctx, run) require.NoError(t, err) require.False(t, restart) // assert that run should be in "paused" state require.Equal(t, pipeline.RunStatusSuspended, run.State) - r, start, err := orm.UpdateTaskRunResult(ds1_id, pipeline.Result{Value: "foo"}) + r, start, err := orm.UpdateTaskRunResult(ctx, ds1_id, pipeline.Result{Value: "foo"}) run = &r require.NoError(t, err) assert.Greater(t, run.ID, int64(0)) @@ -555,6 +564,7 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { } func Test_PipelineORM_DeleteRun(t *testing.T) { + ctx := testutils.Context(t) _, orm, jorm := setupLiteORM(t) run := mustInsertAsyncRun(t, orm, jorm) @@ -582,21 +592,22 @@ func Test_PipelineORM_DeleteRun(t *testing.T) { FinishedAt: null.TimeFrom(now), }, } - restart, err := orm.StoreRun(run) + restart, err := orm.StoreRun(ctx, run) require.NoError(t, err) // no new data, so we don't need a restart require.Equal(t, false, restart) // the run is paused require.Equal(t, pipeline.RunStatusSuspended, run.State) - err = orm.DeleteRun(run.ID) + err = orm.DeleteRun(ctx, run.ID) require.NoError(t, err) - _, err = orm.FindRun(run.ID) + _, err = orm.FindRun(ctx, run.ID) require.Error(t, err, "not found") } func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { + ctx := testutils.Context(t) _, orm, jorm := setupHeavyORM(t) var runsIds []int64 @@ -623,7 +634,7 @@ func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { run.Outputs = jsonserializable.JSONSerializable{Val: 1, Valid: true} run.AllErrors = pipeline.RunErrors{null.StringFrom("SOMETHING")} - restart, err := orm.StoreRun(run) + restart, err := orm.StoreRun(ctx, run) assert.NoError(t, err) // no new data, so we don't need a restart assert.Equal(t, false, restart) @@ -635,13 +646,14 @@ func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { assert.NoError(t, err) for _, runId := range runsIds { - _, err := orm.FindRun(runId) + _, err := orm.FindRun(ctx, runId) require.Error(t, err, "not found") } } func Test_GetUnfinishedRuns_Keepers(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) // The test configures single Keeper job with two running tasks. // GetUnfinishedRuns() expects to catch both running tasks. @@ -649,8 +661,8 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { config := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - porm := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + keyStore := cltest.NewKeyStore(t, db) + porm := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db) jorm := job.NewORM(db, porm, bridgeORM, keyStore, lggr, config.Database()) @@ -684,7 +696,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { runID1 := uuid.New() runID2 := uuid.New() - err = porm.CreateRun(&pipeline.Run{ + err = porm.CreateRun(ctx, &pipeline.Run{ PipelineSpecID: keeperJob.PipelineSpecID, PruningKey: keeperJob.ID, State: pipeline.RunStatusRunning, @@ -701,7 +713,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { }) require.NoError(t, err) - err = porm.CreateRun(&pipeline.Run{ + err = porm.CreateRun(ctx, &pipeline.Run{ PipelineSpecID: keeperJob.PipelineSpecID, PruningKey: keeperJob.ID, State: pipeline.RunStatusRunning, @@ -744,6 +756,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) // The test configures single DR job with two task runs: one is running and one is suspended. // GetUnfinishedRuns() expects to catch the one that is running. @@ -751,8 +764,8 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { config := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db, config.Database()) - porm := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) + keyStore := cltest.NewKeyStore(t, db) + porm := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db) jorm := job.NewORM(db, porm, bridgeORM, keyStore, lggr, config.Database()) @@ -784,7 +797,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { runningID := uuid.New() - err = porm.CreateRun(&pipeline.Run{ + err = porm.CreateRun(ctx, &pipeline.Run{ PipelineSpecID: drJob.PipelineSpecID, PruningKey: drJob.ID, State: pipeline.RunStatusRunning, @@ -801,7 +814,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { }) require.NoError(t, err) - err = porm.CreateRun(&pipeline.Run{ + err = porm.CreateRun(ctx, &pipeline.Run{ PipelineSpecID: drJob.PipelineSpecID, PruningKey: drJob.ID, State: pipeline.RunStatusSuspended, @@ -846,7 +859,7 @@ func Test_Prune(t *testing.T) { }) lggr, observed := logger.TestLoggerObserved(t, zapcore.DebugLevel) db := pgtest.NewSqlxDB(t) - porm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + porm := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) torm := newTestORM(porm, db) ps1 := cltest.MustInsertPipelineSpec(t, db) diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 08d371716fc..862d2f49178 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -15,6 +15,7 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -36,15 +36,16 @@ type Runner interface { // Run is a blocking call that will execute the run until no further progress can be made. // If `incomplete` is true, the run is only partially complete and is suspended, awaiting to be resumed when more data comes in. // Note that `saveSuccessfulTaskRuns` value is ignored if the run contains async tasks. - Run(ctx context.Context, run *Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(tx pg.Queryer) error) (incomplete bool, err error) - ResumeRun(taskID uuid.UUID, value interface{}, err error) error + Run(ctx context.Context, run *Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(tx sqlutil.DataSource) error) (incomplete bool, err error) + ResumeRun(ctx context.Context, taskID uuid.UUID, value interface{}, err error) error // ExecuteRun executes a new run in-memory according to a spec and returns the results. // We expect spec.JobID and spec.JobName to be set for logging/prometheus. ExecuteRun(ctx context.Context, spec Spec, vars Vars, l logger.Logger) (run *Run, trrs TaskRunResults, err error) // InsertFinishedRun saves the run results in the database. - InsertFinishedRun(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error - InsertFinishedRuns(runs []*Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error + // ds is an optional override, for example when executing a transaction. + InsertFinishedRun(ctx context.Context, ds sqlutil.DataSource, run *Run, saveSuccessfulTaskRuns bool) error + InsertFinishedRuns(ctx context.Context, ds sqlutil.DataSource, runs []*Run, saveSuccessfulTaskRuns bool) error // ExecuteAndInsertFinishedRun executes a new run in-memory according to a spec, persists and saves the results. // It is a combination of ExecuteRun and InsertFinishedRun. @@ -566,9 +567,9 @@ func (r *runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec Spec, var } if spec.ID == 0 { - err = r.orm.InsertFinishedRunWithSpec(run, saveSuccessfulTaskRuns) + err = r.orm.InsertFinishedRunWithSpec(ctx, run, saveSuccessfulTaskRuns) } else { - err = r.orm.InsertFinishedRun(run, saveSuccessfulTaskRuns) + err = r.orm.InsertFinishedRun(ctx, run, saveSuccessfulTaskRuns) } if err != nil { return 0, trrs, pkgerrors.Wrapf(err, "error inserting finished results for spec ID %v", run.PipelineSpecID) @@ -577,7 +578,7 @@ func (r *runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec Spec, var } -func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(tx pg.Queryer) error) (incomplete bool, err error) { +func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(tx sqlutil.DataSource) error) (incomplete bool, err error) { pipeline, err := r.InitializePipeline(run.PipelineSpec) if err != nil { return false, err @@ -594,8 +595,7 @@ func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccess preinsert := pipeline.RequiresPreInsert() - q := r.orm.GetQ().WithOpts(pg.WithParentCtx(ctx)) - err = q.Transaction(func(tx pg.Queryer) error { + err = r.orm.Transact(ctx, func(tx ORM) error { // OPTIMISATION: avoid an extra db write if there is no async tasks present or if this is a resumed run if preinsert && run.ID == 0 { now := time.Now() @@ -614,13 +614,13 @@ func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccess default: } } - if err = r.orm.CreateRun(run, pg.WithQueryer(tx)); err != nil { + if err = tx.CreateRun(ctx, run); err != nil { return err } } if fn != nil { - return fn(tx) + return fn(tx.DataSource()) } return nil }) @@ -634,14 +634,14 @@ func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccess if preinsert { // FailSilently = run failed and task was marked failEarly. skip StoreRun and instead delete all trace of it if run.FailSilently { - if err = r.orm.DeleteRun(run.ID); err != nil { + if err = r.orm.DeleteRun(ctx, run.ID); err != nil { return false, pkgerrors.Wrap(err, "Run") } return false, nil } var restart bool - restart, err = r.orm.StoreRun(run) + restart, err = r.orm.StoreRun(ctx, run) if err != nil { return false, pkgerrors.Wrapf(err, "error storing run for spec ID %v state %v outputs %v errors %v finished_at %v", run.PipelineSpec.ID, run.State, run.Outputs, run.FatalErrors, run.FinishedAt) @@ -660,7 +660,7 @@ func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccess return false, nil } - if err = r.orm.InsertFinishedRun(run, saveSuccessfulTaskRuns, pg.WithParentCtx(ctx)); err != nil { + if err = r.orm.InsertFinishedRun(ctx, run, saveSuccessfulTaskRuns); err != nil { return false, pkgerrors.Wrapf(err, "error storing run for spec ID %v", run.PipelineSpec.ID) } } @@ -671,8 +671,8 @@ func (r *runner) Run(ctx context.Context, run *Run, l logger.Logger, saveSuccess } } -func (r *runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error { - run, start, err := r.orm.UpdateTaskRunResult(taskID, Result{ +func (r *runner) ResumeRun(ctx context.Context, taskID uuid.UUID, value interface{}, err error) error { + run, start, err := r.orm.UpdateTaskRunResult(ctx, taskID, Result{ Value: value, Error: err, }) @@ -694,12 +694,20 @@ func (r *runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error return nil } -func (r *runner) InsertFinishedRun(run *Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - return r.orm.InsertFinishedRun(run, saveSuccessfulTaskRuns, qopts...) +func (r *runner) InsertFinishedRun(ctx context.Context, ds sqlutil.DataSource, run *Run, saveSuccessfulTaskRuns bool) error { + orm := r.orm + if ds != nil { + orm = orm.WithDataSource(ds) + } + return orm.InsertFinishedRun(ctx, run, saveSuccessfulTaskRuns) } -func (r *runner) InsertFinishedRuns(runs []*Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { - return r.orm.InsertFinishedRuns(runs, saveSuccessfulTaskRuns, qopts...) +func (r *runner) InsertFinishedRuns(ctx context.Context, ds sqlutil.DataSource, runs []*Run, saveSuccessfulTaskRuns bool) error { + orm := r.orm + if ds != nil { + orm = orm.WithDataSource(ds) + } + return orm.InsertFinishedRuns(ctx, runs, saveSuccessfulTaskRuns) } func (r *runner) runReaper() { diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 52e668339ec..e086d5297ef 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -43,7 +43,7 @@ import ( func newRunner(t testing.TB, db *sqlx.DB, bridgeORM bridges.ORM, cfg chainlink.GeneralConfig) (pipeline.Runner, *mocks.ORM) { lggr := logger.TestLogger(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := mocks.NewORM(t) @@ -476,11 +476,11 @@ func Test_PipelineRunner_HandleFaultsPersistRun(t *testing.T) { orm.On("GetQ").Return(q).Maybe() orm.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(1).(*pipeline.Run).ID = 1 }). Return(nil) cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) lggr := logger.TestLogger(t) @@ -517,11 +517,11 @@ func Test_PipelineRunner_ExecuteAndInsertFinishedRun_SavingTheSpec(t *testing.T) orm.On("GetQ").Return(q).Maybe() orm.On("InsertFinishedRunWithSpec", mock.Anything, mock.Anything, mock.Anything). Run(func(args mock.Arguments) { - args.Get(0).(*pipeline.Run).ID = 1 + args.Get(1).(*pipeline.Run).ID = 1 }). Return(nil) cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) lggr := logger.TestLogger(t) @@ -642,7 +642,13 @@ func Test_PipelineRunner_AsyncJob_Basic(t *testing.T) { btORM := bridgesMocks.NewORM(t) btORM.On("FindBridge", mock.Anything, bt.Name).Return(*bt, nil) + r, orm := newRunner(t, db, btORM, cfg) + transactCall := orm.On("Transact", mock.Anything, mock.Anything) + transactCall.Run(func(args mock.Arguments) { + fn := args[1].(func(orm pipeline.ORM) error) + transactCall.ReturnArguments = mock.Arguments{fn(orm)} + }) s := fmt.Sprintf(` ds1 [type=bridge async=true name="%s" timeout=0 requestData=<{"data": {"coin": "BTC", "market": "USD"}}>] @@ -673,11 +679,11 @@ ds5 [type=http method="GET" url="%s" index=2] // Start a new run run := pipeline.NewRun(spec, pipeline.NewVarsFrom(nil)) // we should receive a call to CreateRun because it's contains an async task - orm.On("CreateRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { - run := args.Get(0).(*pipeline.Run) + orm.On("CreateRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(nil).Run(func(args mock.Arguments) { + run := args.Get(1).(*pipeline.Run) run.ID = 1 // give it a valid "id" }).Once() - orm.On("StoreRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(false, nil).Once() + orm.On("StoreRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(false, nil).Once() lggr := logger.TestLogger(t) incomplete, err := r.Run(testutils.Context(t), run, lggr, false, nil) require.NoError(t, err) @@ -687,7 +693,7 @@ ds5 [type=http method="GET" url="%s" index=2] // TODO: test a pending run that's not marked async=true, that is not allowed // Trigger run resumption with no new data - orm.On("StoreRun", mock.AnythingOfType("*pipeline.Run")).Return(false, nil).Once() + orm.On("StoreRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(false, nil).Once() incomplete, err = r.Run(testutils.Context(t), run, lggr, false, nil) require.NoError(t, err) require.Equal(t, true, incomplete) // still incomplete @@ -700,7 +706,7 @@ ds5 [type=http method="GET" url="%s" index=2] Valid: true, } // Trigger run resumption - orm.On("StoreRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(false, nil).Once() + orm.On("StoreRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(false, nil).Once() incomplete, err = r.Run(testutils.Context(t), run, lggr, false, nil) require.NoError(t, err) require.Equal(t, false, incomplete) // done @@ -770,6 +776,11 @@ func Test_PipelineRunner_AsyncJob_InstantRestart(t *testing.T) { btORM.On("FindBridge", mock.Anything, bt.Name).Return(*bt, nil) r, orm := newRunner(t, db, btORM, cfg) + transactCall := orm.On("Transact", mock.Anything, mock.Anything) + transactCall.Run(func(args mock.Arguments) { + fn := args[1].(func(orm pipeline.ORM) error) + transactCall.ReturnArguments = mock.Arguments{fn(orm)} + }) s := fmt.Sprintf(` ds1 [type=bridge async=true name="%s" timeout=0 requestData=<{"data": {"coin": "BTC", "market": "USD"}}>] @@ -800,13 +811,13 @@ ds5 [type=http method="GET" url="%s" index=2] // Start a new run run := pipeline.NewRun(spec, pipeline.NewVarsFrom(nil)) // we should receive a call to CreateRun because it's contains an async task - orm.On("CreateRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { - run := args.Get(0).(*pipeline.Run) + orm.On("CreateRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(nil).Run(func(args mock.Arguments) { + run := args.Get(1).(*pipeline.Run) run.ID = 1 // give it a valid "id" }).Once() // Simulate updated task run data - orm.On("StoreRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(true, nil).Run(func(args mock.Arguments) { - run := args.Get(0).(*pipeline.Run) + orm.On("StoreRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(true, nil).Run(func(args mock.Arguments) { + run := args.Get(1).(*pipeline.Run) // Now simulate a new result coming in while we were running task := run.ByDotID("ds1") task.Error = null.NewString("", false) @@ -816,7 +827,7 @@ ds5 [type=http method="GET" url="%s" index=2] } }).Once() // StoreRun is called again to store the final result - orm.On("StoreRun", mock.AnythingOfType("*pipeline.Run"), mock.Anything).Return(false, nil).Once() + orm.On("StoreRun", mock.Anything, mock.AnythingOfType("*pipeline.Run")).Return(false, nil).Once() incomplete, err := r.Run(testutils.Context(t), run, logger.TestLogger(t), false, nil) require.NoError(t, err) require.Len(t, run.PipelineTaskRuns, 12) @@ -991,7 +1002,7 @@ func Test_PipelineRunner_ExecuteRun(t *testing.T) { t.Run("uses cached *Pipeline if available", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) lggr := logger.TestLogger(t) diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index 922f82a533b..029c6c78ca8 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -216,8 +216,8 @@ func TestBridgeTask_Happy(t *testing.T) { RequestData: btcUSDPairing, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -258,8 +258,8 @@ func TestBridgeTask_HandlesIntermittentFailure(t *testing.T) { CacheTTL: "30s", // standard duration string format } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) result, runInfo := task.Run(testutils.Context(t), logger.TestLogger(t), @@ -321,8 +321,8 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { RequestData: btcUSDPairing, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -481,8 +481,8 @@ func TestBridgeTask_AsyncJobPendingState(t *testing.T) { Async: "true", } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, id, c) @@ -659,8 +659,8 @@ func TestBridgeTask_Variables(t *testing.T) { IncludeInputAtKey: test.includeInputAtKey, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -728,8 +728,8 @@ func TestBridgeTask_Meta(t *testing.T) { Name: bridge.Name.String(), } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -782,8 +782,8 @@ func TestBridgeTask_IncludeInputAtKey(t *testing.T) { IncludeInputAtKey: test.includeInputAtKey, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -838,8 +838,8 @@ func TestBridgeTask_ErrorMessage(t *testing.T) { RequestData: ethUSDPairing, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -877,8 +877,8 @@ func TestBridgeTask_OnlyErrorMessage(t *testing.T) { RequestData: ethUSDPairing, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -902,8 +902,8 @@ func TestBridgeTask_ErrorIfBridgeMissing(t *testing.T) { } c := clhttptest.NewTestLocalOnlyHTTPClient() orm := bridges.NewORM(db) - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -992,8 +992,8 @@ func TestBridgeTask_Headers(t *testing.T) { } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -1014,8 +1014,8 @@ func TestBridgeTask_Headers(t *testing.T) { } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -1036,8 +1036,8 @@ func TestBridgeTask_Headers(t *testing.T) { } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) @@ -1082,8 +1082,8 @@ func TestBridgeTask_AdapterResponseStatusFailure(t *testing.T) { RequestData: btcUSDPairing, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) diff --git a/core/services/pipeline/task.http_test.go b/core/services/pipeline/task.http_test.go index ce28fac478c..6264d1e591b 100644 --- a/core/services/pipeline/task.http_test.go +++ b/core/services/pipeline/task.http_test.go @@ -24,7 +24,6 @@ import ( clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -177,8 +176,8 @@ func TestHTTPTask_Variables(t *testing.T) { RequestData: test.requestData, } c := clhttptest.NewTestLocalOnlyHTTPClient() - trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(testutils.Context(t), nil, pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute)) require.NoError(t, err) task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 1d9c2a69087..bb09b86df95 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -34,7 +34,7 @@ func newHead() evmtypes.Head { func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - keyStore := cltest.NewKeyStore(t, db, dbConfig).Eth() + keyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) lggr := logger.TestLogger(t) @@ -96,9 +96,8 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { t.Run("with unconfirmed evm.txes", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) var subscribeCalls atomic.Int32 diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 1a09e681f8a..e9aaa7e0a8e 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -520,11 +520,10 @@ func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rarg if opts.subjectID != nil { subject = *opts.subjectID } - scoped := configWatcher.chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(subject, scoped.OCR2().DefaultTransactionQueueDepth(), scoped.Database().DefaultQueryTimeout()) + strategy := txmgrcommon.NewQueueingTxStrategy(subject, relayConfig.DefaultTransactionQueueDepth) var checker txm.TransmitCheckerSpec - if configWatcher.chain.Config().OCR2().SimulateTransactions() { + if relayConfig.SimulateTransactions { checker.CheckerType = txm.TransmitCheckerTypeSimulate } diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index ed7b247f46b..f10874da149 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -182,11 +182,10 @@ func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32 fromAddresses = append(fromAddresses, common.HexToAddress(s)) } - scoped := configWatcher.chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(rargs.ExternalJobID, scoped.OCR2().DefaultTransactionQueueDepth(), scoped.Database().DefaultQueryTimeout()) + strategy := txmgrcommon.NewQueueingTxStrategy(rargs.ExternalJobID, relayConfig.DefaultTransactionQueueDepth) var checker txm.TransmitCheckerSpec - if configWatcher.chain.Config().OCR2().SimulateTransactions() { + if relayConfig.SimulateTransactions { checker.CheckerType = txm.TransmitCheckerTypeSimulate } diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index fb50f6941b2..c0ca43e23ca 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -22,7 +22,6 @@ import ( txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/ocr2/plugins/functions/encoding" @@ -38,8 +37,7 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() digestStr := "000130da6b9315bd59af6b0a3f5463c0d0a39e92eaa34cbcbdbace7b3bfcc776" lggr := logger.TestLogger(t) @@ -90,8 +88,7 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() contractVersion := uint32(1) configuredDestAddress, coordinatorAddress := testutils.NewAddress(), testutils.NewAddress() @@ -169,8 +166,7 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() contractVersion := uint32(1) configuredDestAddress, coordinatorAddress1, coordinatorAddress2 := testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress() diff --git a/core/services/relay/evm/mercury/mocks/async_deleter.go b/core/services/relay/evm/mercury/mocks/async_deleter.go index b706e9c771e..6a43c1a0568 100644 --- a/core/services/relay/evm/mercury/mocks/async_deleter.go +++ b/core/services/relay/evm/mercury/mocks/async_deleter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 5e7335af06d..9b2fed8423a 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mocks/request_round_db.go b/core/services/relay/evm/mocks/request_round_db.go index 725fc6e6b37..d1aa15a3b5b 100644 --- a/core/services/relay/evm/mocks/request_round_db.go +++ b/core/services/relay/evm/mocks/request_round_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks @@ -9,6 +9,8 @@ import ( mock "github.com/stretchr/testify/mock" ocr2aggregator "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + + sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" ) // RequestRoundDB is an autogenerated mock type for the RequestRoundDB type @@ -62,19 +64,21 @@ func (_m *RequestRoundDB) SaveLatestRoundRequested(ctx context.Context, rr ocr2a return r0 } -// Transact provides a mock function with given fields: _a0, _a1 -func (_m *RequestRoundDB) Transact(_a0 context.Context, _a1 func(evm.RequestRoundDB) error) error { - ret := _m.Called(_a0, _a1) +// WithDataSource provides a mock function with given fields: _a0 +func (_m *RequestRoundDB) WithDataSource(_a0 sqlutil.DataSource) evm.RequestRoundDB { + ret := _m.Called(_a0) if len(ret) == 0 { - panic("no return value specified for Transact") + panic("no return value specified for WithDataSource") } - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, func(evm.RequestRoundDB) error) error); ok { - r0 = rf(_a0, _a1) + var r0 evm.RequestRoundDB + if rf, ok := ret.Get(0).(func(sqlutil.DataSource) evm.RequestRoundDB); ok { + r0 = rf(_a0) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).(evm.RequestRoundDB) + } } return r0 diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index af15461aee9..b9a6433c3a7 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -22,6 +22,7 @@ import ( func TestChainRelayExtenders(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) newId := testutils.NewRandomEVMChainID() cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -31,8 +32,8 @@ func TestChainRelayExtenders(t *testing.T) { c.EVM = append(c.EVM, &toml.EVMConfig{ChainID: ubig.New(newId), Enabled: &t, Chain: toml.Defaults(nil)}) }) db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db, cfg.Database()) - require.NoError(t, kst.Unlock(cltest.Password)) + kst := cltest.NewKeyStore(t, db) + require.NoError(t, kst.Unlock(ctx, cltest.Password)) opts := evmtest.NewChainRelayExtOpts(t, evmtest.TestChainOpts{DB: db, KeyStore: kst.Eth(), GeneralConfig: cfg}) opts.GenEthClient = func(*big.Int) evmclient.Client { diff --git a/core/services/relay/evm/request_round_db.go b/core/services/relay/evm/request_round_db.go index 2b6ae10782d..96c5a05d1c7 100644 --- a/core/services/relay/evm/request_round_db.go +++ b/core/services/relay/evm/request_round_db.go @@ -12,16 +12,17 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" ) +//go:generate mockery --quiet --name RequestRoundDB --output ./mocks/ --case=underscore + // RequestRoundDB stores requested rounds for querying by the median plugin. type RequestRoundDB interface { SaveLatestRoundRequested(ctx context.Context, rr ocr2aggregator.OCR2AggregatorRoundRequested) error LoadLatestRoundRequested(context.Context) (rr ocr2aggregator.OCR2AggregatorRoundRequested, err error) - Transact(context.Context, func(db RequestRoundDB) error) error + WithDataSource(sqlutil.DataSource) RequestRoundDB } var _ RequestRoundDB = &requestRoundDB{} -//go:generate mockery --quiet --name RequestRoundDB --output ./mocks/ --case=underscore type requestRoundDB struct { ds sqlutil.DataSource oracleSpecID int32 @@ -33,10 +34,8 @@ func NewRoundRequestedDB(ds sqlutil.DataSource, oracleSpecID int32, lggr logger. return &requestRoundDB{ds, oracleSpecID, lggr} } -func (d *requestRoundDB) Transact(ctx context.Context, fn func(db RequestRoundDB) error) error { - return sqlutil.Transact(ctx, func(ds sqlutil.DataSource) RequestRoundDB { - return NewRoundRequestedDB(ds, d.oracleSpecID, d.lggr) - }, d.ds, nil, fn) +func (d *requestRoundDB) WithDataSource(ds sqlutil.DataSource) RequestRoundDB { + return NewRoundRequestedDB(ds, d.oracleSpecID, d.lggr) } func (d *requestRoundDB) SaveLatestRoundRequested(ctx context.Context, rr ocr2aggregator.OCR2AggregatorRoundRequested) error { diff --git a/core/services/relay/evm/request_round_db_test.go b/core/services/relay/evm/request_round_db_test.go index 10932c4e229..26f8e2ac1a6 100644 --- a/core/services/relay/evm/request_round_db_test.go +++ b/core/services/relay/evm/request_round_db_test.go @@ -37,9 +37,7 @@ func Test_DB_LatestRoundRequested(t *testing.T) { t.Run("saves latest round requested", func(t *testing.T) { ctx := testutils.Context(t) - err := db.Transact(ctx, func(tx evm.RequestRoundDB) error { - return tx.SaveLatestRoundRequested(ctx, rr) - }) + err := db.SaveLatestRoundRequested(ctx, rr) require.NoError(t, err) rawLog.Index = 42 @@ -53,9 +51,7 @@ func Test_DB_LatestRoundRequested(t *testing.T) { Raw: rawLog, } - err = db.Transact(ctx, func(tx evm.RequestRoundDB) error { - return tx.SaveLatestRoundRequested(ctx, rr) - }) + err = db.SaveLatestRoundRequested(ctx, rr) require.NoError(t, err) }) diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go index bb39271f278..fe6b6826eb2 100644 --- a/core/services/relay/evm/request_round_tracker.go +++ b/core/services/relay/evm/request_round_tracker.go @@ -106,8 +106,8 @@ func (t *RequestRoundTracker) Close() error { // HandleLog complies with LogListener interface // It is not thread safe -func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { - was, err := t.logBroadcaster.WasAlreadyConsumed(t.ctx, lb) +func (t *RequestRoundTracker) HandleLog(ctx context.Context, lb log.Broadcast) { + was, err := t.logBroadcaster.WasAlreadyConsumed(ctx, lb) if err != nil { t.lggr.Errorw("OCRContract: could not determine if log was already consumed", "err", err) return @@ -118,12 +118,12 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { raw := lb.RawLog() if raw.Address != t.contract.Address() { t.lggr.Errorf("log address of 0x%x does not match configured contract address of 0x%x", raw.Address, t.contract.Address()) - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(ctx, nil, lb), "unable to mark consumed") return } topics := raw.Topics if len(topics) == 0 { - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(ctx, nil, lb), "unable to mark consumed") return } @@ -134,16 +134,15 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { rr, err = t.contractFilterer.ParseRoundRequested(raw) if err != nil { t.lggr.Errorw("could not parse round requested", "err", err) - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(ctx, nil, lb), "unable to mark consumed") return } if IsLaterThan(raw, t.latestRoundRequested.Raw) { - ctx := context.TODO() //TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 - err = t.odb.Transact(ctx, func(tx RequestRoundDB) error { - if err = tx.SaveLatestRoundRequested(ctx, *rr); err != nil { + err = sqlutil.TransactDataSource(ctx, t.ds, nil, func(tx sqlutil.DataSource) error { + if err = t.odb.WithDataSource(tx).SaveLatestRoundRequested(ctx, *rr); err != nil { return err } - return t.logBroadcaster.MarkConsumed(t.ctx, lb) + return t.logBroadcaster.MarkConsumed(ctx, tx, lb) }) if err != nil { t.lggr.Error(err) @@ -161,7 +160,7 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { t.lggr.Debugw("RequestRoundTracker: got unrecognised log topic", "topic", topics[0]) } if !consumed { - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(ctx, nil, lb), "unable to mark consumed") } } diff --git a/core/services/relay/evm/request_round_tracker_test.go b/core/services/relay/evm/request_round_tracker_test.go index 9feb4b77348..6af6c593a2b 100644 --- a/core/services/relay/evm/request_round_tracker_test.go +++ b/core/services/relay/evm/request_round_tracker_test.go @@ -14,9 +14,9 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -52,13 +52,10 @@ type contractTrackerUni struct { } func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrackerUni) { - var chain evmconfig.ChainScopedConfig var filterer *ocr2aggregator.OCR2AggregatorFilterer var contract *offchain_aggregator_wrapper.OffchainAggregator for _, opt := range opts { switch v := opt.(type) { - case evmconfig.ChainScopedConfig: - chain = v case *ocr2aggregator.OCR2AggregatorFilterer: filterer = v case *offchain_aggregator_wrapper.OffchainAggregator: @@ -67,9 +64,8 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack t.Fatalf("unrecognised option type %T", v) } } - if chain == nil { - chain = evmtest.NewChainScopedConfig(t, configtest.NewTestGeneralConfig(t)) - } + config := configtest.NewTestGeneralConfig(t) + chain := evmtest.NewChainScopedConfig(t, config) if filterer == nil { filterer = mustNewFilterer(t, testutils.NewAddress()) } @@ -112,7 +108,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin rawLog := cltest.LogFromFixture(t, "../../../testdata/jsonrpc/ocr2_round_requested_log_1_1.json") logBroadcast.On("RawLog").Return(rawLog).Maybe() logBroadcast.On("String").Return("").Maybe() - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) configDigest, epoch, round, err := uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) @@ -121,7 +117,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin require.Equal(t, 0, int(round)) require.Equal(t, 0, int(epoch)) - uni.requestRoundTracker.HandleLog(logBroadcast) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -143,7 +139,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin require.Equal(t, 0, int(round)) require.Equal(t, 0, int(epoch)) - uni.requestRoundTracker.HandleLog(logBroadcast) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -168,19 +164,14 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast.On("RawLog").Return(rawLog).Maybe() logBroadcast.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr ocr2aggregator.OCR2AggregatorRoundRequested) bool { return rr.Epoch == 1 && rr.Round == 1 })).Return(nil) - transact := uni.db.On("Transact", mock.Anything, mock.Anything) - transact.Run(func(args mock.Arguments) { - fn := args[1].(func(evm.RequestRoundDB) error) - err2 := fn(uni.db) - transact.ReturnArguments = []any{err2} - }) + uni.db.On("WithDataSource", mock.Anything).Return(uni.db) - uni.requestRoundTracker.HandleLog(logBroadcast) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -194,13 +185,13 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast2.On("RawLog").Return(rawLog2).Maybe() logBroadcast2.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr ocr2aggregator.OCR2AggregatorRoundRequested) bool { return rr.Epoch == 1 && rr.Round == 9 })).Return(nil) - uni.requestRoundTracker.HandleLog(logBroadcast2) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast2) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -209,7 +200,7 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin assert.Equal(t, 9, int(round)) // Same round with lower epoch is ignored - uni.requestRoundTracker.HandleLog(logBroadcast) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -224,13 +215,13 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin logBroadcast3.On("RawLog").Return(rawLog3).Maybe() logBroadcast3.On("String").Return("").Maybe() uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) + uni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.MatchedBy(func(rr ocr2aggregator.OCR2AggregatorRoundRequested) bool { return rr.Epoch == 2 && rr.Round == 1 })).Return(nil) - uni.requestRoundTracker.HandleLog(logBroadcast3) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast3) configDigest, epoch, round, err = uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) @@ -250,14 +241,9 @@ func Test_OCRContractTracker_HandleLog_OCRContractLatestRoundRequested(t *testin uni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) uni.db.On("SaveLatestRoundRequested", mock.Anything, mock.Anything).Return(errors.New("something exploded")) - transact := uni.db.On("Transact", mock.Anything, mock.Anything) - transact.Run(func(args mock.Arguments) { - fn := args[1].(func(evm.RequestRoundDB) error) - err := fn(uni.db) - transact.ReturnArguments = []any{err} - }) + uni.db.On("WithDataSource", mock.Anything).Return(uni.db) - uni.requestRoundTracker.HandleLog(logBroadcast) + uni.requestRoundTracker.HandleLog(tests.Context(t), logBroadcast) configDigest, epoch, round, err := uni.requestRoundTracker.LatestRoundRequested(testutils.Context(t), 0) require.NoError(t, err) diff --git a/core/services/relay/evm/types/mocks/log_poller_wrapper.go b/core/services/relay/evm/types/mocks/log_poller_wrapper.go index 8017e983e53..46a0b08d0c3 100644 --- a/core/services/relay/evm/types/mocks/log_poller_wrapper.go +++ b/core/services/relay/evm/types/mocks/log_poller_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index ea794262bd4..26e1c6f7128 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -113,6 +113,9 @@ type RelayConfig struct { ChainReader *ChainReaderConfig `json:"chainReader"` Codec *CodecConfig `json:"codec"` + DefaultTransactionQueueDepth uint32 `json:"defaultTransactionQueueDepth"` + SimulateTransactions bool `json:"simulateTransactions"` + // Contract-specific SendingKeys pq.StringArray `json:"sendingKeys"` diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index db8cb03d431..b4cc4517390 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -3,73 +3,11 @@ package relay import ( "context" "fmt" - "regexp" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" ) -type Network = string -type ChainID = string - -const ( - EVM = "evm" - Cosmos = "cosmos" - Solana = "solana" - StarkNet = "starknet" -) - -var SupportedRelays = map[Network]struct{}{ - EVM: {}, - Cosmos: {}, - Solana: {}, - StarkNet: {}, -} - -// ID uniquely identifies a relayer by network and chain id -type ID struct { - Network Network - ChainID ChainID -} - -func (i *ID) Name() string { - return fmt.Sprintf("%s.%s", i.Network, i.ChainID) -} - -func (i *ID) String() string { - return i.Name() -} -func NewID(n Network, c ChainID) ID { - return ID{Network: n, ChainID: c} -} - -var idRegex = regexp.MustCompile( - fmt.Sprintf("^((%s)|(%s)|(%s)|(%s))\\.", EVM, Cosmos, Solana, StarkNet), -) - -func (i *ID) UnmarshalString(s string) error { - idxs := idRegex.FindStringIndex(s) - if idxs == nil { - return fmt.Errorf("error unmarshaling Identifier. %q does not match expected pattern", s) - } - // ignore the `.` in the match by dropping last rune - network := s[idxs[0] : idxs[1]-1] - chainID := s[idxs[1]:] - newID := &ID{ChainID: chainID} - for n := range SupportedRelays { - if network == n { - newID.Network = n - break - } - } - if newID.Network == "" { - return fmt.Errorf("error unmarshaling identifier: did not find network in supported list %q", network) - } - i.ChainID = newID.ChainID - i.Network = newID.Network - return nil -} - // ServerAdapter extends [loop.RelayerAdapter] by overriding NewPluginProvider to dispatches calls according to `RelayArgs.ProviderType`. // This should only be used to adapt relayers not running via GRPC in a LOOPP. type ServerAdapter struct { diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index dc12b769609..c0b2248ed1a 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -15,53 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) -func TestIdentifier_UnmarshalString(t *testing.T) { - type fields struct { - Network Network - ChainID ChainID - } - type args struct { - s string - } - tests := []struct { - name string - want fields - args args - wantErr bool - }{ - {name: "evm", - args: args{s: "evm.1"}, - wantErr: false, - want: fields{Network: EVM, ChainID: "1"}, - }, - {name: "bad network", - args: args{s: "notANetwork.1"}, - wantErr: true, - }, - {name: "bad pattern", - args: args{s: "evm_1"}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - i := &ID{} - err := i.UnmarshalString(tt.args.s) - if (err != nil) != tt.wantErr { - t.Errorf("Identifier.UnmarshalString() error = %v, wantErr %v", err, tt.wantErr) - } - assert.Equal(t, tt.want.Network, i.Network) - assert.Equal(t, tt.want.ChainID, i.ChainID) - }) - } -} - -func TestNewID(t *testing.T) { - rid := NewID(EVM, "chain id") - assert.Equal(t, EVM, rid.Network) - assert.Equal(t, "chain id", rid.ChainID) -} - type staticMedianProvider struct { } diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index 4a5d7fa992d..f616623eb89 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/s4/mocks/storage.go b/core/services/s4/mocks/storage.go index 06fc153a358..5971b9f1ece 100644 --- a/core/services/s4/mocks/storage.go +++ b/core/services/s4/mocks/storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/streams/delegate.go b/core/services/streams/delegate.go index f9e2a64c4a3..bf492d4bd15 100644 --- a/core/services/streams/delegate.go +++ b/core/services/streams/delegate.go @@ -12,7 +12,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -38,10 +37,10 @@ func (d *Delegate) JobType() job.Type { return job.Stream } -func (d *Delegate) BeforeJobCreated(jb job.Job) {} -func (d *Delegate) AfterJobCreated(jb job.Job) {} -func (d *Delegate) BeforeJobDeleted(jb job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(jb job.Job) {} +func (d *Delegate) AfterJobCreated(jb job.Job) {} +func (d *Delegate) BeforeJobDeleted(jb job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { if jb.StreamID == nil { diff --git a/core/services/streams/stream_test.go b/core/services/streams/stream_test.go index 3c0b4d0721f..3e8f58cd58b 100644 --- a/core/services/streams/stream_test.go +++ b/core/services/streams/stream_test.go @@ -11,9 +11,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -32,7 +32,7 @@ func (m *mockRunner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pi func (m *mockRunner) InitializePipeline(spec pipeline.Spec) (p *pipeline.Pipeline, err error) { return m.p, m.err } -func (m *mockRunner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, qopts ...pg.QOpt) error { +func (m *mockRunner) InsertFinishedRun(ctx context.Context, ds sqlutil.DataSource, run *pipeline.Run, saveSuccessfulTaskRuns bool) error { return m.err } diff --git a/core/services/synchronization/mocks/telemetry_service.go b/core/services/synchronization/mocks/telemetry_service.go index 375b46ad7bb..b705d49aecd 100644 --- a/core/services/synchronization/mocks/telemetry_service.go +++ b/core/services/synchronization/mocks/telemetry_service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index b8dbb5e5d37..cade98cf606 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -113,7 +113,7 @@ func (tc *telemetryIngressBatchClient) Start(ctx context.Context) error { if ctx2.Err() != nil { tc.lggr.Warnw("gave up connecting to telemetry endpoint", "err", err) } else { - tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err) + tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err, "server pubkey", tc.serverPubKeyHex) tc.SvcErrBuffer.Append(err) } return diff --git a/core/services/synchronization/telemetry_ingress_client_test.go b/core/services/synchronization/telemetry_ingress_client_test.go index 55be107b977..e7e14eda748 100644 --- a/core/services/synchronization/telemetry_ingress_client_test.go +++ b/core/services/synchronization/telemetry_ingress_client_test.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" + telem "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" ) func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { @@ -33,7 +34,7 @@ func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { // Wire up the telem ingress client url := &url.URL{} - serverPubKeyHex := "33333333333" + serverPubKeyHex := telem.GetDummyKeyString() telemIngressClient := synchronization.NewTestTelemetryIngressClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient) servicetest.Run(t, telemIngressClient) diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 2d3409ba569..9b83ef08234 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -79,21 +79,21 @@ func TestNewManager(t *testing.T) { network: "NETWORK-1", chainID: "NETWORK-1-CHAINID-1", url: "http://network-1-chainID-1.test", - pubKey: "network-1-chainID-1-pub-key", + pubKey: GetDummyKeyStringWithPrefix("network-1-chainID-1-pub-key"), shouldError: false, }, { network: "NETWORK-1", chainID: "NETWORK-1-CHAINID-2", url: "http://network-1-chainID-2.test", - pubKey: "network-1-chainID-2-pub-key", + pubKey: GetDummyKeyStringWithPrefix("network-1-chainID-2-pub-key"), shouldError: false, }, { network: "NETWORK-2", chainID: "NETWORK-2-CHAINID-1", url: "http://network-2-chainID-1.test", - pubKey: "network-2-chainID-1-pub-key", + pubKey: GetDummyKeyStringWithPrefix("network-2-chainID-1-pub-key"), shouldError: false, }, { @@ -122,7 +122,7 @@ func TestNewManager(t *testing.T) { network: "NETWORK-1", chainID: "NETWORK-1-CHAINID-1", url: "http://network-1-chainID-1.test", - pubKey: "network-1-chainID-1-pub-key", + pubKey: GetDummyKeyStringWithPrefix("network-1-chainID-1-pub-key"), shouldError: true, expectedError: "endpoint already exists", }, diff --git a/core/services/telemetry/test_helpers.go b/core/services/telemetry/test_helpers.go new file mode 100644 index 00000000000..408b46666f1 --- /dev/null +++ b/core/services/telemetry/test_helpers.go @@ -0,0 +1,20 @@ +package telemetry + +import ( + "fmt" +) + +var keyString = fmt.Sprintf("%064b", 0) + +// getDummyKeyString returns a dummy key string +// satisfies the wsrpc key length constraints +func GetDummyKeyString() string { + return keyString +} + +// getDummyKeyString returns a dummy key string with the specified prefix +// satisfies the wsrpc key length constraints +func GetDummyKeyStringWithPrefix(prefix string) string { + combo := prefix + GetDummyKeyString() + return combo[:64] +} diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 617a28ac4d5..c5b4df3f811 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -2,6 +2,7 @@ package vrf import ( "context" + "encoding/json" "fmt" "time" @@ -11,8 +12,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "go.uber.org/multierr" - "github.com/jmoiron/sqlx" - + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -26,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" v1 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v1" v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" @@ -34,7 +33,7 @@ import ( ) type Delegate struct { - q pg.Q + ds sqlutil.DataSource pr pipeline.Runner porm pipeline.ORM ks keystore.Master @@ -44,16 +43,15 @@ type Delegate struct { } func NewDelegate( - db *sqlx.DB, + ds sqlutil.DataSource, ks keystore.Master, pr pipeline.Runner, porm pipeline.ORM, legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, - cfg pg.QConfig, mailMon *mailbox.Monitor) *Delegate { return &Delegate{ - q: pg.NewQ(db, lggr, cfg), + ds: ds, ks: ks, pr: pr, porm: porm, @@ -67,16 +65,29 @@ func (d *Delegate) JobType() job.Type { return job.VRF } -func (d *Delegate) BeforeJobCreated(job.Job) {} -func (d *Delegate) AfterJobCreated(job.Job) {} -func (d *Delegate) BeforeJobDeleted(job.Job) {} -func (d *Delegate) OnDeleteJob(context.Context, job.Job, pg.Queryer) error { return nil } +func (d *Delegate) BeforeJobCreated(job.Job) {} +func (d *Delegate) AfterJobCreated(job.Job) {} +func (d *Delegate) BeforeJobDeleted(job.Job) {} +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { if jb.VRFSpec == nil || jb.PipelineSpec == nil { return nil, errors.Errorf("vrf.Delegate expects a VRFSpec and PipelineSpec to be present, got %+v", jb) } + marshalledVRFSpec, err := json.MarshalIndent(jb.VRFSpec, "", " ") + if err != nil { + return nil, err + } + marshalledPipelineSpec, err := json.MarshalIndent(jb.PipelineSpec, "", " ") + if err != nil { + return nil, err + } + d.lggr.Debugw("Creating services for job spec", + "vrfSpec", string(marshalledVRFSpec), + "pipelineSpec", string(marshalledPipelineSpec), + "keyHash", jb.VRFSpec.PublicKey.MustHash(), + ) pl, err := jb.PipelineSpec.ParsePipeline() if err != nil { return nil, err @@ -171,7 +182,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi lV2Plus, chain, chain.ID(), - d.q, + d.ds, v2.NewCoordinatorV2_5(coordinatorV2Plus), batchCoordinatorV2, vrfOwner, @@ -225,7 +236,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi lV2, chain, chain.ID(), - d.q, + d.ds, v2.NewCoordinatorV2(coordinatorV2), batchCoordinatorV2, vrfOwner, @@ -246,7 +257,6 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi Cfg: chain.Config().EVM(), FeeCfg: chain.Config().EVM().GasEstimator(), L: logger.Sugared(lV1), - Q: d.q, Coordinator: coordinator, PipelineRunner: d.pr, GethKs: d.ks.Eth(), diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 000577d9d4b..a3962977257 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -67,6 +67,7 @@ type vrfUniverse struct { } func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniverse { + ctx := testutils.Context(t) // Mock all chain interactions lb := log_mocks.NewBroadcaster(t) lb.On("AddDependents", 1).Maybe() @@ -78,9 +79,9 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv hb := headtracker.NewHeadBroadcaster(lggr) // Don't mock db interactions - prm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + prm := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) txm, err := txmgr.NewTxm(db, db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), nil, dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, ks.Eth(), nil) orm := headtracker.NewORM(*testutils.FixtureChainID, db) @@ -90,12 +91,12 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{LogBroadcaster: lb, KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) - require.NoError(t, ks.Unlock(testutils.Password)) + require.NoError(t, ks.Unlock(ctx, testutils.Password)) k, err2 := ks.Eth().Create(testutils.Context(t), testutils.FixtureChainID) require.NoError(t, err2) submitter := k.Address require.NoError(t, err) - vrfkey, err3 := ks.VRF().Create() + vrfkey, err3 := ks.VRF().Create(ctx) require.NoError(t, err3) return vrfUniverse{ @@ -160,7 +161,6 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { vuni.prm, vuni.legacyChains, logger.TestLogger(t), - cfg.Database(), mailMon) vs := testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: vuni.vrfkey.PublicKey.String(), EVMChainID: testutils.FixtureChainID.String()}) jb, err := vrfcommon.ValidatedVRFSpec(vs.Toml()) @@ -201,9 +201,10 @@ func TestDelegate_ReorgAttackProtection(t *testing.T) { preSeed := common.BigToHash(big.NewInt(42)).Bytes() txHash := evmutils.NewHash() vuni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Maybe() - vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Maybe() + vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe() vuni.ec.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(generateCallbackReturnValues(t, false), nil).Maybe() - listener.HandleLog(log.NewLogBroadcast(types.Log{ + ctx := testutils.Context(t) + listener.HandleLog(ctx, log.NewLogBroadcast(types.Log{ // Data has all the NON-indexed parameters Data: bytes.Join([][]byte{pk.MustHash().Bytes(), // key hash preSeed, // preSeed @@ -302,14 +303,15 @@ func TestDelegate_ValidLog(t *testing.T) { consumed := make(chan struct{}) for i, tc := range tt { tc := tc + ctx := testutils.Context(t) vuni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { consumed <- struct{}{} }).Return(nil).Once() // Expect a call to check if the req is already fulfilled. vuni.ec.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(generateCallbackReturnValues(t, false), nil) - listener.HandleLog(log.NewLogBroadcast(tc.log, vuni.cid, nil)) + listener.HandleLog(ctx, log.NewLogBroadcast(tc.log, vuni.cid, nil)) // Wait until the log is present waitForChannel(t, added, time.Second, "request not added to the queue") // Feed it a head which confirms it. @@ -318,7 +320,7 @@ func TestDelegate_ValidLog(t *testing.T) { // Ensure we created a successful run. waitForChannel(t, runComplete, 2*time.Second, "pipeline not complete") - runs, err := vuni.prm.GetAllRuns() + runs, err := vuni.prm.GetAllRuns(ctx) require.NoError(t, err) require.Equal(t, i+1, len(runs)) assert.False(t, runs[0].FatalErrors.HasError()) @@ -328,13 +330,13 @@ func TestDelegate_ValidLog(t *testing.T) { p, err := vuni.ks.VRF().GenerateProof(keyID, evmutils.MustHash(string(bytes.Join([][]byte{preSeed, bh.Bytes()}, []byte{}))).Big()) require.NoError(t, err) vuni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { consumed <- struct{}{} }).Return(nil).Once() // If we send a completed log we should the respCount increase var reqIDBytes []byte copy(reqIDBytes[:], tc.reqID[:]) - listener.HandleLog(log.NewLogBroadcast(types.Log{ + listener.HandleLog(ctx, log.NewLogBroadcast(types.Log{ // Data has all the NON-indexed parameters Data: bytes.Join([][]byte{reqIDBytes, // output p.Output.Bytes(), @@ -354,7 +356,7 @@ func TestDelegate_InvalidLog(t *testing.T) { vuni, listener, jb := setup(t) vuni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) done := make(chan struct{}) - vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { done <- struct{}{} }).Return(nil).Once() // Expect a call to check if the req is already fulfilled. @@ -365,7 +367,8 @@ func TestDelegate_InvalidLog(t *testing.T) { added <- struct{}{} }) // Send an invalid log (keyhash doesnt match) - listener.HandleLog(log.NewLogBroadcast(types.Log{ + ctx := testutils.Context(t) + listener.HandleLog(ctx, log.NewLogBroadcast(types.Log{ // Data has all the NON-indexed parameters Data: append(append(append(append( evmutils.NewHash().Bytes(), // key hash @@ -392,7 +395,7 @@ func TestDelegate_InvalidLog(t *testing.T) { waitForChannel(t, done, time.Second, "log not consumed") // Should create a run that errors in the vrf task - runs, err := vuni.prm.GetAllRuns() + runs, err := vuni.prm.GetAllRuns(ctx) require.NoError(t, err) require.Equal(t, len(runs), 1) for _, tr := range runs[0].PipelineTaskRuns { @@ -417,7 +420,7 @@ func TestFulfilledCheck(t *testing.T) { vuni, listener, jb := setup(t) vuni.lb.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) done := make(chan struct{}) - vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + vuni.lb.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { done <- struct{}{} }).Return(nil).Once() // Expect a call to check if the req is already fulfilled. @@ -429,7 +432,8 @@ func TestFulfilledCheck(t *testing.T) { added <- struct{}{} }) // Send an invalid log (keyhash doesn't match) - listener.HandleLog(log.NewLogBroadcast( + ctx := testutils.Context(t) + listener.HandleLog(ctx, log.NewLogBroadcast( types.Log{ // Data has all the NON-indexed parameters Data: bytes.Join([][]byte{ @@ -455,7 +459,7 @@ func TestFulfilledCheck(t *testing.T) { waitForChannel(t, done, time.Second, "log not consumed") // Should consume the log with no run - runs, err := vuni.prm.GetAllRuns() + runs, err := vuni.prm.GetAllRuns(ctx) require.NoError(t, err) require.Equal(t, len(runs), 0) } @@ -556,11 +560,11 @@ decode_log->vrf->encode_tx->submit_tx func Test_CheckFromAddressesExist(t *testing.T) { t.Run("from addresses exist", func(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) - require.NoError(t, ks.Unlock(testutils.Password)) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, testutils.Password)) var fromAddresses []string for i := 0; i < 3; i++ { @@ -584,11 +588,11 @@ func Test_CheckFromAddressesExist(t *testing.T) { }) t.Run("one of from addresses doesn't exist", func(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) - require.NoError(t, ks.Unlock(testutils.Password)) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, testutils.Password)) var fromAddresses []string for i := 0; i < 3; i++ { @@ -685,7 +689,6 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { vuni.prm, vuni.legacyChains, logger.TestLogger(t), - cfg.Database(), mailMon) chain, err := vuni.legacyChains.Get(testutils.FixtureChainID.String()) require.NoError(t, err) diff --git a/core/services/vrf/mocks/aggregator_v3_interface.go b/core/services/vrf/mocks/aggregator_v3_interface.go index 46ca11aa200..65351354d7a 100644 --- a/core/services/vrf/mocks/aggregator_v3_interface.go +++ b/core/services/vrf/mocks/aggregator_v3_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index b46a28ec037..3685e17b0ff 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index ee7ea4e9a58..0d62898862b 100644 --- a/core/services/vrf/mocks/fee_config.go +++ b/core/services/vrf/mocks/fee_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/vrf_coordinator_v2.go b/core/services/vrf/mocks/vrf_coordinator_v2.go index 529bc789257..e8c1467e44f 100644 --- a/core/services/vrf/mocks/vrf_coordinator_v2.go +++ b/core/services/vrf/mocks/vrf_coordinator_v2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/proof/proof_response_test.go b/core/services/vrf/proof/proof_response_test.go index c547be2be2c..994ac80b5e2 100644 --- a/core/services/vrf/proof/proof_response_test.go +++ b/core/services/vrf/proof/proof_response_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_verifier_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" proof2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -22,11 +22,11 @@ import ( ) func TestMarshaledProof(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + keyStore := cltest.NewKeyStore(t, db) key := cltest.DefaultVRFKey - require.NoError(t, keyStore.VRF().Add(key)) + require.NoError(t, keyStore.VRF().Add(ctx, key)) blockHash := common.Hash{} blockNum := 0 preSeed := big.NewInt(1) diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index f68700a8af7..c28ad9ce3d0 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -45,6 +45,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { + ctx := testutils.Context(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) @@ -75,7 +76,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { } var runs []pipeline.Run gomega.NewWithT(t).Eventually(func() bool { - runs, err = app.PipelineORM().GetAllRuns() + runs, err = app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) // It possible that we send the test request // before the Job spawner has started the vrf services, which is fine @@ -128,6 +129,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { func TestIntegration_VRF_WithBHS(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].BlockBackfillDepth = ptr[uint32](500) @@ -196,7 +198,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { var runs []pipeline.Run gomega.NewWithT(t).Eventually(func() bool { - runs, err = app.PipelineORM().GetAllRuns() + runs, err = app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) cu.Backend.Commit() return len(runs) == 1 && runs[0].State == pipeline.RunStatusCompleted @@ -231,7 +233,8 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { } func createVRFJobRegisterKey(t *testing.T, u vrftesthelpers.CoordinatorUniverse, app *cltest.TestApplication, incomingConfs int) (job.Job, vrfkey.KeyV2) { - vrfKey, err := app.KeyStore.VRF().Create() + ctx := testutils.Context(t) + vrfKey, err := app.KeyStore.VRF().Create(ctx) require.NoError(t, err) jid := uuid.MustParse("96a8a26f-d426-4784-8d8f-fb387d4d8345") diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index c57265634e5..ddf5779deb0 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -17,6 +17,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" @@ -303,17 +304,16 @@ func (lsn *Listener) RunLogListener(unsubscribes []func(), minConfs uint32) { break } recovery.WrapRecover(lsn.L, func() { - lsn.handleLog(lb, minConfs) + ctx, cancel := lsn.ChStop.NewCtx() + defer cancel() + lsn.handleLog(ctx, lb, minConfs) }) } } } } -func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { - ctx, cancel := lsn.ChStop.NewCtx() - defer cancel() - +func (lsn *Listener) handleLog(ctx context.Context, lb log.Broadcast, minConfs uint32) { lggr := lsn.L.With( "log", lb.String(), "decodedLog", lb.DecodedLog(), @@ -380,7 +380,7 @@ func (lsn *Listener) shouldProcessLog(ctx context.Context, lb log.Broadcast) boo } func (lsn *Listener) markLogAsConsumed(ctx context.Context, lb log.Broadcast) { - err := lsn.Chain.LogBroadcaster().MarkConsumed(ctx, lb) + err := lsn.Chain.LogBroadcaster().MarkConsumed(ctx, nil, lb) lsn.L.ErrorIf(err, fmt.Sprintf("Unable to mark log %v as consumed", lb.String())) } @@ -486,9 +486,10 @@ func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { run := pipeline.NewRun(*lsn.Job.PipelineSpec, vars) // The VRF pipeline has no async tasks, so we don't need to check for `incomplete` - if _, err = lsn.PipelineRunner.Run(ctx, run, lggr, true, func(tx pg.Queryer) error { + if _, err = lsn.PipelineRunner.Run(ctx, run, lggr, true, func(tx sqlutil.DataSource) error { // Always mark consumed regardless of whether the proof failed or not. - if err = lsn.Chain.LogBroadcaster().MarkConsumed(ctx, req.lb); err != nil { + //TODO restore tx https://smartcontract-it.atlassian.net/browse/BCF-2978 + if err = lsn.Chain.LogBroadcaster().MarkConsumed(ctx, nil, req.lb); err != nil { lggr.Errorw("Failed mark consumed", "err", err) } return nil @@ -525,7 +526,7 @@ func (lsn *Listener) Close() error { }) } -func (lsn *Listener) HandleLog(lb log.Broadcast) { +func (lsn *Listener) HandleLog(ctx context.Context, lb log.Broadcast) { if !lsn.Deduper.ShouldDeliver(lb.RawLog()) { lsn.L.Tracew("skipping duplicate log broadcast", "log", lb.RawLog()) return diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index f19f39f03f2..2e0554fca96 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -62,6 +62,7 @@ func testSingleConsumerHappyPath( rwfe v22.RandomWordsFulfilled, subID *big.Int), ) { + ctx := testutils.Context(t) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) @@ -87,7 +88,7 @@ func testSingleConsumerHappyPath( // Fund gas lanes. sendEth(t, ownerKey, uni.backend, key1.Address, 10) sendEth(t, ownerKey, uni.backend, key2.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job using key1 and key2 on the same gas lane. jbs := createVRFJobs( @@ -111,7 +112,7 @@ func testSingleConsumerHappyPath( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -133,7 +134,7 @@ func testSingleConsumerHappyPath( requestID2, _ := requestRandomnessAndAssertRandomWordsRequestedEvent(t, consumerContract, consumer, keyHash, subID, numWords, 500_000, coordinator, uni.backend, nativePayment) gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 2 @@ -153,11 +154,11 @@ func testSingleConsumerHappyPath( assertNumRandomWords(t, consumerContract, numWords) // Assert that both send addresses were used to fulfill the requests - n, err := uni.backend.PendingNonceAt(testutils.Context(t), key1.Address) + n, err := uni.backend.PendingNonceAt(ctx, key1.Address) require.NoError(t, err) require.EqualValues(t, 1, n) - n, err = uni.backend.PendingNonceAt(testutils.Context(t), key2.Address) + n, err = uni.backend.PendingNonceAt(ctx, key2.Address) require.NoError(t, err) require.EqualValues(t, 1, n) @@ -182,6 +183,7 @@ func testMultipleConsumersNeedBHS( coordinator v22.CoordinatorV2_X, rwfe v22.RandomWordsFulfilled), ) { + ctx := testutils.Context(t) nConsumers := len(consumers) vrfKey := cltest.MustGenerateRandomKey(t) sendEth(t, ownerKey, uni.backend, vrfKey.Address, 10) @@ -216,7 +218,7 @@ func testMultipleConsumersNeedBHS( }) keys = append(keys, ownerKey, vrfKey) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, keys...) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. vrfJobs := createVRFJobs( @@ -250,7 +252,7 @@ func testMultipleConsumersNeedBHS( // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) - require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Replay(testutils.Context(t), 1)) + require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Replay(ctx, 1)) for i := 0; i < nConsumers; i++ { consumer := consumers[i] @@ -284,7 +286,7 @@ func testMultipleConsumersNeedBHS( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -320,6 +322,7 @@ func testMultipleConsumersNeedTrustedBHS( coordinator v22.CoordinatorV2_X, rwfe v22.RandomWordsFulfilled), ) { + ctx := testutils.Context(t) nConsumers := len(consumers) vrfKey := cltest.MustGenerateRandomKey(t) sendEth(t, ownerKey, uni.backend, vrfKey.Address, 10) @@ -364,7 +367,7 @@ func testMultipleConsumersNeedTrustedBHS( }) keys = append(keys, ownerKey, vrfKey) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, keys...) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. vrfJobs := createVRFJobs( @@ -403,7 +406,7 @@ func testMultipleConsumersNeedTrustedBHS( // Ensure log poller is ready and has all logs. chain := app.GetRelayers().LegacyEVMChains().Slice()[0] require.NoError(t, chain.LogPoller().Ready()) - require.NoError(t, chain.LogPoller().Replay(testutils.Context(t), 1)) + require.NoError(t, chain.LogPoller().Replay(ctx, 1)) for i := 0; i < nConsumers; i++ { consumer := consumers[i] @@ -445,7 +448,7 @@ func testMultipleConsumersNeedTrustedBHS( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -534,6 +537,7 @@ func testSingleConsumerHappyPathBatchFulfillment( rwfe v22.RandomWordsFulfilled, subID *big.Int), ) { + ctx := testutils.Context(t) key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -555,7 +559,7 @@ func testSingleConsumerHappyPathBatchFulfillment( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job using key1 and key2 on the same gas lane. jbs := createVRFJobs( @@ -590,7 +594,7 @@ func testSingleConsumerHappyPathBatchFulfillment( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) if bigGasCallback { @@ -640,6 +644,7 @@ func testSingleConsumerNeedsTopUp( coordinator v22.CoordinatorV2_X, rwfe v22.RandomWordsFulfilled), ) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(1000) config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -659,7 +664,7 @@ func testSingleConsumerNeedsTopUp( // Fund expensive gas lane. sendEth(t, ownerKey, uni.backend, key.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -682,7 +687,7 @@ func testSingleConsumerNeedsTopUp( // Fulfillment will not be enqueued because subscriber doesn't have enough LINK. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 1", "runs", len(runs)) return len(runs) == 0 @@ -695,7 +700,7 @@ func testSingleConsumerNeedsTopUp( // Wait for fulfillment to go through. gomega.NewWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 2", "runs", len(runs)) return len(runs) == 1 @@ -737,6 +742,7 @@ func testBlockHeaderFeeder( coordinator v22.CoordinatorV2_X, rwfe v22.RandomWordsFulfilled), ) { + ctx := testutils.Context(t) nConsumers := len(consumers) vrfKey := cltest.MustGenerateRandomKey(t) @@ -760,7 +766,7 @@ func testBlockHeaderFeeder( c.EVM[0].FinalityDepth = ptr[uint32](2) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, vrfKey, bhfKey) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. vrfJobs := createVRFJobs( @@ -792,7 +798,7 @@ func testBlockHeaderFeeder( // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) - require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Replay(testutils.Context(t), 1)) + require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Replay(ctx, 1)) for i := 0; i < nConsumers; i++ { consumer := consumers[i] @@ -821,7 +827,7 @@ func testBlockHeaderFeeder( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -900,6 +906,7 @@ func testSingleConsumerForcedFulfillment( batchEnabled bool, vrfVersion vrfcommon.Version, ) { + ctx := testutils.Context(t) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) @@ -951,7 +958,7 @@ func testSingleConsumerForcedFulfillment( // Fund gas lanes. sendEth(t, ownerKey, uni.backend, key1.Address, 10) sendEth(t, ownerKey, uni.backend, key2.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job using key1 and key2 on the same gas lane. jbs := createVRFJobs( @@ -1065,6 +1072,7 @@ func testSingleConsumerEIP150( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) callBackGasLimit := int64(2_500_000) // base callback gas. key1 := cltest.MustGenerateRandomKey(t) @@ -1090,7 +1098,7 @@ func testSingleConsumerEIP150( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1114,7 +1122,7 @@ func testSingleConsumerEIP150( // Wait for simulation to pass. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1132,6 +1140,7 @@ func testSingleConsumerEIP150Revert( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) callBackGasLimit := int64(2_500_000) // base callback gas. eip150Fee := int64(0) // no premium given for callWithExactGas coordinatorFulfillmentOverhead := int64(90_000) // fixed gas used in coordinator fulfillment @@ -1160,7 +1169,7 @@ func testSingleConsumerEIP150Revert( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1184,7 +1193,7 @@ func testSingleConsumerEIP150Revert( // Simulation should not pass. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 0 @@ -1202,6 +1211,7 @@ func testSingleConsumerBigGasCallbackSandwich( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) key1 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(100) config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -1224,7 +1234,7 @@ func testSingleConsumerBigGasCallbackSandwich( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1253,7 +1263,7 @@ func testSingleConsumerBigGasCallbackSandwich( // Assert that we've completed 0 runs before adding 3 new requests. { - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) assert.Equal(t, 0, len(runs)) assert.Equal(t, 3, len(reqIDs)) @@ -1262,7 +1272,7 @@ func testSingleConsumerBigGasCallbackSandwich( // Wait for the 50_000 gas randomness request to be enqueued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1271,7 +1281,7 @@ func testSingleConsumerBigGasCallbackSandwich( // After the first successful request, no more will be enqueued. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 1", "runs", len(runs)) return len(runs) == 1 @@ -1285,7 +1295,7 @@ func testSingleConsumerBigGasCallbackSandwich( // Assert that we've still only completed 1 run before adding new requests. { - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) assert.Equal(t, 1, len(runs)) } @@ -1300,7 +1310,7 @@ func testSingleConsumerBigGasCallbackSandwich( // Fulfillment will not be enqueued because subscriber doesn't have enough LINK for any of the requests. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 1", "runs", len(runs)) return len(runs) == 1 @@ -1318,6 +1328,7 @@ func testSingleConsumerMultipleGasLanes( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) cheapKey := cltest.MustGenerateRandomKey(t) expensiveKey := cltest.MustGenerateRandomKey(t) cheapGasLane := assets.GWei(10) @@ -1349,7 +1360,7 @@ func testSingleConsumerMultipleGasLanes( // Fund gas lanes. sendEth(t, ownerKey, uni.backend, cheapKey.Address, 10) sendEth(t, ownerKey, uni.backend, expensiveKey.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF jobs. jbs := createVRFJobs( @@ -1374,7 +1385,7 @@ func testSingleConsumerMultipleGasLanes( // Wait for fulfillment to be queued for cheap key hash. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 1", "runs", len(runs)) return len(runs) == 1 @@ -1394,7 +1405,7 @@ func testSingleConsumerMultipleGasLanes( // We should not have any new fulfillments until a top up. gomega.NewWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 2", "runs", len(runs)) return len(runs) == 1 @@ -1406,7 +1417,7 @@ func testSingleConsumerMultipleGasLanes( // Wait for fulfillment to be queued for expensive key hash. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("assert 1", "runs", len(runs)) return len(runs) == 2 @@ -1442,6 +1453,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -1464,7 +1476,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1488,7 +1500,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1511,6 +1523,7 @@ func testConsumerProxyHappyPath( vrfVersion vrfcommon.Version, nativePayment bool, ) { + ctx := testutils.Context(t) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) @@ -1540,7 +1553,7 @@ func testConsumerProxyHappyPath( // Create gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) sendEth(t, ownerKey, uni.backend, key2.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job using key1 and key2 on the same gas lane. jbs := createVRFJobs( @@ -1565,7 +1578,7 @@ func testConsumerProxyHappyPath( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1591,7 +1604,7 @@ func testConsumerProxyHappyPath( t, consumerContract, consumerOwner, keyHash, subID, numWords, 750_000, uni.rootContract, uni.backend, nativePayment) gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 2 @@ -1603,11 +1616,11 @@ func testConsumerProxyHappyPath( assertNumRandomWords(t, consumerContract, numWords) // Assert that both send addresses were used to fulfill the requests - n, err := uni.backend.PendingNonceAt(testutils.Context(t), key1.Address) + n, err := uni.backend.PendingNonceAt(ctx, key1.Address) require.NoError(t, err) require.EqualValues(t, 1, n) - n, err = uni.backend.PendingNonceAt(testutils.Context(t), key2.Address) + n, err = uni.backend.PendingNonceAt(ctx, key2.Address) require.NoError(t, err) require.EqualValues(t, 1, n) @@ -1644,6 +1657,7 @@ func testMaliciousConsumer( batchEnabled bool, vrfVersion vrfcommon.Version, ) { + ctx := testutils.Context(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint64](2_000_000) c.EVM[0].GasEstimator.PriceMax = assets.GWei(1) @@ -1656,11 +1670,11 @@ func testMaliciousConsumer( carol := uni.vrfConsumers[0] app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) - err := app.GetKeyStore().Unlock(cltest.Password) + err := app.GetKeyStore().Unlock(ctx, cltest.Password) require.NoError(t, err) - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) jid := uuid.New() @@ -1702,7 +1716,7 @@ func testMaliciousConsumer( // by the node. var attempts []txmgr.TxAttempt gomega.NewWithT(t).Eventually(func() bool { - attempts, _, err = app.TxmStorageService().TxAttempts(testutils.Context(t), 0, 1000) + attempts, _, err = app.TxmStorageService().TxAttempts(ctx, 0, 1000) require.NoError(t, err) // It possible that we send the test request // before the job spawner has started the vrf services, which is fine @@ -1716,7 +1730,7 @@ func testMaliciousConsumer( // The fulfillment tx should succeed ch, err := app.GetRelayers().LegacyEVMChains().Get(evmtest.MustGetDefaultChainID(t, config.EVMConfigs()).String()) require.NoError(t, err) - r, err := ch.Client().TransactionReceipt(testutils.Context(t), attempts[0].Hash) + r, err := ch.Client().TransactionReceipt(ctx, attempts[0].Hash) require.NoError(t, err) require.Equal(t, uint64(1), r.Status) @@ -1759,6 +1773,7 @@ func testReplayOldRequestsOnStartUp( rwfe v22.RandomWordsFulfilled, subID *big.Int), ) { + ctx := testutils.Context(t) sendingKey := cltest.MustGenerateRandomKey(t) gasLanePriceWei := assets.GWei(10) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -1778,10 +1793,10 @@ func testReplayOldRequestsOnStartUp( // Fund gas lanes. sendEth(t, ownerKey, uni.backend, sendingKey.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF Key, register it to coordinator and export - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) registerProvingKeyHelper(t, uni, coordinator, vrfkey, &defaultMaxGasPrice) keyHash := vrfkey.PublicKey.MustHash() @@ -1816,9 +1831,9 @@ func testReplayOldRequestsOnStartUp( // Start a new app and create VRF job using the same VRF key created above app = cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, sendingKey) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) - vrfKey, err := app.GetKeyStore().VRF().Import(encodedVrfKey, testutils.Password) + vrfKey, err := app.GetKeyStore().VRF().Import(ctx, encodedVrfKey, testutils.Password) require.NoError(t, err) incomingConfs := 2 @@ -1863,7 +1878,7 @@ func testReplayOldRequestsOnStartUp( // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index bfec76afec3..b885473e488 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -847,6 +847,7 @@ func TestVRFV2PlusIntegration_TestMaliciousConsumer(t *testing.T) { } func TestVRFV2PlusIntegration_RequestCost(t *testing.T) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, key, 1, false) @@ -854,7 +855,7 @@ func TestVRFV2PlusIntegration_RequestCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey, &defaultMaxGasPrice) t.Run("non-proxied consumer", func(tt *testing.T) { @@ -1002,6 +1003,7 @@ func requestAndEstimateFulfillmentCost( } func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, key, 1, false) @@ -1009,7 +1011,7 @@ func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey, &defaultMaxGasPrice) @@ -1141,6 +1143,7 @@ func setupSubscriptionAndFund( func TestVRFV2PlusIntegration_Migration(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 1, false) key1 := cltest.MustGenerateRandomKey(t) @@ -1200,7 +1203,7 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { // Wait for fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 1 diff --git a/core/services/vrf/v2/integration_v2_reverted_txns_test.go b/core/services/vrf/v2/integration_v2_reverted_txns_test.go index b8e6f5f9b05..dfee450b6a2 100644 --- a/core/services/vrf/v2/integration_v2_reverted_txns_test.go +++ b/core/services/vrf/v2/integration_v2_reverted_txns_test.go @@ -411,6 +411,7 @@ func createVRFJobsNew( chainID *big.Int, gasLanePrices ...*assets.Wei, ) (jobs []job.Job, vrfKeyIDs []string) { + ctx := testutils.Context(t) if len(gasLanePrices) != len(fromKeys) { t.Fatalf("must provide one gas lane price for each set of from addresses. len(gasLanePrices) != len(fromKeys) [%d != %d]", len(gasLanePrices), len(fromKeys)) @@ -422,7 +423,7 @@ func createVRFJobsNew( keyStrs = append(keyStrs, k.Address.String()) } - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) jid := uuid.New() diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 1a7c15a2508..543ec943527 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -73,7 +73,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" @@ -466,7 +465,8 @@ func deployOldCoordinator( // Send eth from prefunded account. // Amount is number of ETH not wei. func sendEth(t *testing.T, key ethkey.KeyV2, ec *backends.SimulatedBackend, to common.Address, eth int) { - nonce, err := ec.PendingNonceAt(testutils.Context(t), key.Address) + ctx := testutils.Context(t) + nonce, err := ec.PendingNonceAt(ctx, key.Address) require.NoError(t, err) tx := gethtypes.NewTx(&gethtypes.DynamicFeeTx{ ChainID: testutils.SimulatedChainID, @@ -480,7 +480,7 @@ func sendEth(t *testing.T, key ethkey.KeyV2, ec *backends.SimulatedBackend, to c }) signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(testutils.SimulatedChainID), key.ToEcdsaPrivKey()) require.NoError(t, err) - err = ec.SendTransaction(testutils.Context(t), signedTx) + err = ec.SendTransaction(ctx, signedTx) require.NoError(t, err) ec.Commit() } @@ -531,6 +531,7 @@ func createVRFJobs( batchEnabled bool, gasLanePrices ...*assets.Wei, ) (jobs []job.Job) { + ctx := testutils.Context(t) if len(gasLanePrices) != len(fromKeys) { t.Fatalf("must provide one gas lane price for each set of from addresses. len(gasLanePrices) != len(fromKeys) [%d != %d]", len(gasLanePrices), len(fromKeys)) @@ -542,7 +543,7 @@ func createVRFJobs( keyStrs = append(keyStrs, k.Address.String()) } - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) jid := uuid.New() @@ -996,7 +997,9 @@ func testEoa( batchingEnabled bool, batchCoordinatorAddress common.Address, vrfOwnerAddress *common.Address, - vrfVersion vrfcommon.Version) { + vrfVersion vrfcommon.Version, +) { + ctx := testutils.Context(t) gasLimit := int64(2_500_000) finalityDepth := uint32(50) @@ -1030,7 +1033,7 @@ func testEoa( // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1059,7 +1062,7 @@ func testEoa( // Ensure request is not fulfilled. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 0 @@ -1069,10 +1072,9 @@ func testEoa( var broadcastsBeforeFinality []evmlogger.LogBroadcast var broadcastsAfterFinality []evmlogger.LogBroadcast query := `SELECT block_hash, consumed, log_index, job_id FROM log_broadcasts` - q := pg.NewQ(app.GetSqlxDB(), app.Logger, app.Config.Database()) // Execute the query. - require.NoError(t, q.Select(&broadcastsBeforeFinality, query)) + require.NoError(t, app.GetDB().SelectContext(ctx, &broadcastsBeforeFinality, query)) // Ensure there is only one log broadcast (our EOA request), and that // it hasn't been marked as consumed yet. @@ -1087,14 +1089,14 @@ func testEoa( // Ensure the request is still not fulfilled. gomega.NewGomegaWithT(t).Consistently(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() + runs, err := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) t.Log("runs", len(runs)) return len(runs) == 0 }, 5*time.Second, time.Second).Should(gomega.BeTrue()) // Execute the query for log broadcasts again after finality depth has elapsed. - require.NoError(t, q.Select(&broadcastsAfterFinality, query)) + require.NoError(t, app.GetDB().SelectContext(ctx, &broadcastsAfterFinality, query)) // Ensure that there is still only one log broadcast (our EOA request), but that // it has been marked as "consumed," such that it won't be retried. @@ -1158,6 +1160,7 @@ func deployWrapper(t *testing.T, uni coordinatorV2UniverseCommon, wrapperOverhea func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) wrapperOverhead := uint32(30_000) coordinatorOverhead := uint32(90_000) @@ -1179,7 +1182,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1221,7 +1224,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { // Wait for simulation to pass. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err2 := app.PipelineORM().GetAllRuns() + runs, err2 := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err2) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1238,6 +1241,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) wrapperOverhead := uint32(30_000) coordinatorOverhead := uint32(90_000) @@ -1261,7 +1265,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { // Fund gas lane. sendEth(t, ownerKey, uni.backend, key1.Address, 10) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) // Create VRF job. jbs := createVRFJobs( @@ -1303,7 +1307,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { // Wait for simulation to pass. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err2 := app.PipelineORM().GetAllRuns() + runs, err2 := app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err2) t.Log("runs", len(runs)) return len(runs) == 1 @@ -1631,6 +1635,7 @@ func TestSimpleConsumerExample(t *testing.T) { func TestIntegrationVRFV2(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) // Reconfigure the sim chain with a default gas price of 1 gwei, // max gas limit of 2M and a key specific max 10 gwei price. // Keep the prices low so we can operate with small link balance subscriptions. @@ -1650,11 +1655,11 @@ func TestIntegrationVRFV2(t *testing.T) { carolContractAddress := uni.consumerContractAddresses[0] app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, key) - keys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) + keys, err := app.KeyStore.Eth().EnabledKeysForChain(ctx, testutils.SimulatedChainID) require.NoError(t, err) require.Zero(t, key.Cmp(keys[0])) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) var chain legacyevm.Chain chain, err = app.GetRelayers().LegacyEVMChains().Get(testutils.SimulatedChainID.String()) require.NoError(t, err) @@ -1723,7 +1728,7 @@ func TestIntegrationVRFV2(t *testing.T) { // by the node. var runs []pipeline.Run gomega.NewWithT(t).Eventually(func() bool { - runs, err = app.PipelineORM().GetAllRuns() + runs, err = app.PipelineORM().GetAllRuns(ctx) require.NoError(t, err) // It is possible that we send the test request // before the job spawner has started the vrf services, which is fine @@ -1745,7 +1750,7 @@ func TestIntegrationVRFV2(t *testing.T) { return len(rf) == 1 }, testutils.WaitTimeout(t), 500*time.Millisecond).Should(gomega.BeTrue()) assert.True(t, rf[0].Success(), "expected callback to succeed") - fulfillReceipt, err := uni.backend.TransactionReceipt(testutils.Context(t), rf[0].Raw().TxHash) + fulfillReceipt, err := uni.backend.TransactionReceipt(ctx, rf[0].Raw().TxHash) require.NoError(t, err) // Assert all the random words received by the consumer are different and non-zero. @@ -1813,7 +1818,7 @@ func TestIntegrationVRFV2(t *testing.T) { // We should see the response count present require.NoError(t, err) var counts map[string]uint64 - counts, err = listenerV2.GetStartingResponseCountsV2(testutils.Context(t)) + counts, err = listenerV2.GetStartingResponseCountsV2(ctx) require.NoError(t, err) t.Log(counts, rf[0].RequestID().String()) assert.Equal(t, uint64(1), counts[rf[0].RequestID().String()]) @@ -1834,6 +1839,7 @@ func TestMaliciousConsumer(t *testing.T) { } func TestRequestCost(t *testing.T) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, key, 1) @@ -1841,7 +1847,7 @@ func TestRequestCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey, nil) t.Run("non-proxied consumer", func(tt *testing.T) { @@ -1939,6 +1945,7 @@ func TestMaxConsumersCost(t *testing.T) { } func TestFulfillmentCost(t *testing.T) { + ctx := testutils.Context(t) key := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, key, 1) @@ -1946,7 +1953,7 @@ func TestFulfillmentCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - vrfkey, err := app.GetKeyStore().VRF().Create() + vrfkey, err := app.GetKeyStore().VRF().Create(ctx) require.NoError(t, err) registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey, nil) @@ -2046,7 +2053,7 @@ func TestStartingCountsV1(t *testing.T) { ctx := testutils.Context(t) lggr := logger.TestLogger(t) txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) ec := evmclimocks.NewClient(t) ec.On("ConfiguredChainID").Return(testutils.SimulatedChainID) ec.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(2), nil).Maybe() @@ -2063,7 +2070,7 @@ func TestStartingCountsV1(t *testing.T) { counts, err = listenerV1.GetStartingResponseCountsV1(testutils.Context(t)) require.NoError(t, err) assert.Equal(t, 0, len(counts)) - err = ks.Unlock(testutils.Password) + err = ks.Unlock(ctx, testutils.Password) require.NoError(t, err) k, err := ks.Eth().Create(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 71c6e72a06f..e820cff63b7 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -14,6 +14,7 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -29,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" ) @@ -70,7 +70,7 @@ func New( l logger.Logger, chain legacyevm.Chain, chainID *big.Int, - q pg.Q, + ds sqlutil.DataSource, coordinator CoordinatorV2_X, batchCoordinator batch_vrf_coordinator_v2.BatchVRFCoordinatorV2Interface, vrfOwner vrf_owner.VRFOwnerInterface, @@ -93,7 +93,7 @@ func New( vrfOwner: vrfOwner, pipelineRunner: pipelineRunner, job: job, - q: q, + ds: ds, gethks: gethks, chStop: make(chan struct{}), reqAdded: reqAdded, @@ -120,7 +120,7 @@ type listenerV2 struct { pipelineRunner pipeline.Runner job job.Job - q pg.Q + ds sqlutil.DataSource gethks keystore.Eth chStop services.StopChan diff --git a/core/services/vrf/v2/listener_v2_log_listener.go b/core/services/vrf/v2/listener_v2_log_listener.go index 6fbe518411d..2d2c08b8590 100644 --- a/core/services/vrf/v2/listener_v2_log_listener.go +++ b/core/services/vrf/v2/listener_v2_log_listener.go @@ -129,8 +129,13 @@ func (lsn *listenerV2) initializeLastProcessedBlock(ctx context.Context) (lastPr }() numBlocksToReplay := numReplayBlocks(lsn.job.VRFSpec.RequestTimeout, lsn.chain.ID()) - ll.Debugw("running replay on log poller") - err = lp.Replay(ctx, mathutil.Max(latestBlock.FinalizedBlockNumber-numBlocksToReplay, 1)) + replayStartBlock := mathutil.Max(latestBlock.FinalizedBlockNumber-numBlocksToReplay, 1) + ll.Debugw("running replay on log poller", + "numBlocksToReplay", numBlocksToReplay, + "replayStartBlock", replayStartBlock, + "requestTimeout", lsn.job.VRFSpec.RequestTimeout, + ) + err = lp.Replay(ctx, replayStartBlock) if err != nil { return 0, fmt.Errorf("LogPoller.Replay: %w", err) } @@ -414,47 +419,56 @@ func (lsn *listenerV2) handleRequested(requested []RandomWordsRequested, request func numReplayBlocks(requestTimeout time.Duration, chainID *big.Int) int64 { var timeoutSeconds = int64(requestTimeout.Seconds()) switch chainID.String() { - case "1": // eth mainnet - case "3": // eth ropsten - case "4": // eth rinkeby - case "5": // eth goerli - case "11155111": // eth sepolia + case + "1", // eth mainnet + "3", // eth robsten + "4", // eth rinkeby + "5", // eth goerli + "11155111": // eth sepolia // block time is 12s return timeoutSeconds / 12 - case "137": // polygon mainnet - case "80001": // polygon mumbai + case + "137", // polygon mainnet + "80001", // polygon mumbai + "80002": // polygon amoy // block time is 2s return timeoutSeconds / 2 - case "56": // bsc mainnet - case "97": // bsc testnet + case + "56", // bsc mainnet + "97": // bsc testnet // block time is 2s return timeoutSeconds / 2 - case "43114": // avalanche mainnet - case "43113": // avalanche fuji + case + "43114", // avalanche mainnet + "43113": // avalanche fuji // block time is 1s return timeoutSeconds - case "250": // fantom mainnet - case "4002": // fantom testnet + case + "250", // fantom mainnet + "4002": // fantom testnet // block time is 1s return timeoutSeconds - case "42161": // arbitrum mainnet - case "421613": // arbitrum goerli - case "421614": // arbitrum sepolia + case + "42161", // arbitrum mainnet + "421613", // arbitrum goerli + "421614": // arbitrum sepolia // block time is 0.25s in the worst case return timeoutSeconds * 4 - case "10": // optimism mainnet - case "69": // optimism kovan - case "420": // optimism goerli - case "11155420": // optimism sepolia - case "8453": // base mainnet - case "84531": // base goerli - case "84532": // base sepolia + case + "10", // optimism mainnet + "69", // optimism kovan + "420", // optimism goerli + "11155420": // optimism sepolia + // block time is 2s + return timeoutSeconds / 2 + case + "8453", // base mainnet + "84531", // base goerli + "84532": // base sepolia // block time is 2s return timeoutSeconds / 2 default: // assume block time of 1s return timeoutSeconds } - // assume block time of 1s - return timeoutSeconds } diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go index 15b0a5ecbe8..a393aec3ee3 100644 --- a/core/services/vrf/v2/listener_v2_log_listener_test.go +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -64,6 +64,7 @@ func setupVRFLogPollerListenerTH(t *testing.T, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth int64, mockChainUpdateFn func(*evmmocks.Chain, *vrfLogPollerListenerTH)) *vrfLogPollerListenerTH { + ctx := testutils.Context(t) lggr := logger.TestLogger(t) chainID := testutils.NewRandomEVMChainID() @@ -111,9 +112,8 @@ func setupVRFLogPollerListenerTH(t *testing.T, ec.Commit() // Log Poller Listener - cfg := pgtest.NewQConfig(false) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) - require.NoError(t, ks.Unlock("blah")) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, "blah")) j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ RequestedConfsDelay: 10, EVMChainID: chainID.String(), @@ -134,7 +134,6 @@ func setupVRFLogPollerListenerTH(t *testing.T, inflightCache: vrfcommon.NewInflightCache(10), chStop: make(chan struct{}), } - ctx := testutils.Context(t) // Filter registration is idempotent, so we can just call it every time // and retry on errors using the ticker. diff --git a/core/services/vrf/v2/listener_v2_log_processor.go b/core/services/vrf/v2/listener_v2_log_processor.go index db84fb47e3e..673f8618c0b 100644 --- a/core/services/vrf/v2/listener_v2_log_processor.go +++ b/core/services/vrf/v2/listener_v2_log_processor.go @@ -20,6 +20,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -28,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -565,55 +565,53 @@ func (lsn *listenerV2) enqueueForceFulfillment( } // fulfill the request through the VRF owner - err = lsn.q.Transaction(func(tx pg.Queryer) error { - lsn.l.Infow("VRFOwner.fulfillRandomWords vs. VRFCoordinatorV2.fulfillRandomWords", - "vrf_owner.fulfillRandomWords", hexutil.Encode(vrfOwnerABI.Methods["fulfillRandomWords"].ID), - "vrf_coordinator_v2.fulfillRandomWords", hexutil.Encode(coordinatorV2ABI.Methods["fulfillRandomWords"].ID), - ) + lsn.l.Infow("VRFOwner.fulfillRandomWords vs. VRFCoordinatorV2.fulfillRandomWords", + "vrf_owner.fulfillRandomWords", hexutil.Encode(vrfOwnerABI.Methods["fulfillRandomWords"].ID), + "vrf_coordinator_v2.fulfillRandomWords", hexutil.Encode(coordinatorV2ABI.Methods["fulfillRandomWords"].ID), + ) - vrfOwnerAddress1 := lsn.vrfOwner.Address() - vrfOwnerAddressSpec := lsn.job.VRFSpec.VRFOwnerAddress.Address() - lsn.l.Infow("addresses diff", "wrapper_address", vrfOwnerAddress1, "spec_address", vrfOwnerAddressSpec) + vrfOwnerAddress1 := lsn.vrfOwner.Address() + vrfOwnerAddressSpec := lsn.job.VRFSpec.VRFOwnerAddress.Address() + lsn.l.Infow("addresses diff", "wrapper_address", vrfOwnerAddress1, "spec_address", vrfOwnerAddressSpec) - lsn.l.Infow("fulfillRandomWords payload", "proof", p.proof, "commitment", p.reqCommitment.Get(), "payload", p.payload) - txData := hexutil.MustDecode(p.payload) - if err != nil { - return fmt.Errorf("abi pack VRFOwner.fulfillRandomWords: %w", err) - } - estimateGasLimit, err := lsn.chain.Client().EstimateGas(ctx, ethereum.CallMsg{ - From: fromAddress, - To: &vrfOwnerAddressSpec, - Data: txData, - }) - if err != nil { - return fmt.Errorf("failed to estimate gas on VRFOwner.fulfillRandomWords: %w", err) - } + lsn.l.Infow("fulfillRandomWords payload", "proof", p.proof, "commitment", p.reqCommitment.Get(), "payload", p.payload) + txData := hexutil.MustDecode(p.payload) + if err != nil { + err = fmt.Errorf("abi pack VRFOwner.fulfillRandomWords: %w", err) + return + } + estimateGasLimit, err := lsn.chain.Client().EstimateGas(ctx, ethereum.CallMsg{ + From: fromAddress, + To: &vrfOwnerAddressSpec, + Data: txData, + }) + if err != nil { + err = fmt.Errorf("failed to estimate gas on VRFOwner.fulfillRandomWords: %w", err) + return + } - lsn.l.Infow("Estimated gas limit on force fulfillment", - "estimateGasLimit", estimateGasLimit, "pipelineGasLimit", p.gasLimit) - if estimateGasLimit < p.gasLimit { - estimateGasLimit = p.gasLimit - } + lsn.l.Infow("Estimated gas limit on force fulfillment", + "estimateGasLimit", estimateGasLimit, "pipelineGasLimit", p.gasLimit) + if estimateGasLimit < p.gasLimit { + estimateGasLimit = p.gasLimit + } - requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) - subID := p.req.req.SubID() - requestTxHash := p.req.req.Raw().TxHash - etx, err = lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ - FromAddress: fromAddress, - ToAddress: lsn.vrfOwner.Address(), - EncodedPayload: txData, - FeeLimit: estimateGasLimit, - Strategy: txmgrcommon.NewSendEveryStrategy(), - Meta: &txmgr.TxMeta{ - RequestID: &requestID, - SubID: ptr(subID.Uint64()), - RequestTxHash: &requestTxHash, - // No max link since simulation failed - }, - }) - return err + requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) + subID := p.req.req.SubID() + requestTxHash := p.req.req.Raw().TxHash + return lsn.chain.TxManager().CreateTransaction(ctx, txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: lsn.vrfOwner.Address(), + EncodedPayload: txData, + FeeLimit: estimateGasLimit, + Strategy: txmgrcommon.NewSendEveryStrategy(), + Meta: &txmgr.TxMeta{ + RequestID: &requestID, + SubID: ptr(subID.Uint64()), + RequestTxHash: &requestTxHash, + // No max link since simulation failed + }, }) - return } // For an errored pipeline run, wait until the finality depth of the chain to have elapsed, @@ -786,8 +784,8 @@ func (lsn *listenerV2) processRequestsPerSubHelper( ll.Infow("Enqueuing fulfillment") var transaction txmgr.Tx - err = lsn.q.Transaction(func(tx pg.Queryer) error { - if err = lsn.pipelineRunner.InsertFinishedRun(p.run, true, pg.WithQueryer(tx)); err != nil { + err = sqlutil.TransactDataSource(ctx, lsn.ds, nil, func(tx sqlutil.DataSource) error { + if err = lsn.pipelineRunner.InsertFinishedRun(ctx, tx, p.run, true); err != nil { return err } diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 4e9e65bfafc..ac59f1fdb69 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -180,11 +180,11 @@ func addConfirmedEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, } func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - cfg := pgtest.NewQConfig(false) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) - require.NoError(t, ks.Unlock("blah")) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, "blah")) chainID := testutils.SimulatedChainID k, err := ks.Eth().Create(testutils.Context(t), chainID) require.NoError(t, err) @@ -206,8 +206,6 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { chain: chain, } - ctx := testutils.Context(t) - // Insert an unstarted eth tx with link metadata addEthTx(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) start, err := listener.MaybeSubtractReservedLink(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) @@ -262,11 +260,11 @@ func TestMaybeSubtractReservedLinkV2Plus(t *testing.T) { } func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - cfg := pgtest.NewQConfig(false) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) - require.NoError(t, ks.Unlock("blah")) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, "blah")) chainID := testutils.SimulatedChainID k, err := ks.Eth().Create(testutils.Context(t), chainID) require.NoError(t, err) @@ -289,8 +287,6 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) chain: chain, } - ctx := testutils.Context(t) - // Insert an unstarted eth tx with native metadata addEthTxNativePayment(t, txstore, k.Address, txmgrcommon.TxUnstarted, "10000", subID, reqTxHash, vrfVersion) start, err := listener.MaybeSubtractReservedEth(ctx, big.NewInt(100_000), chainID, subID, vrfVersion) @@ -341,11 +337,11 @@ func TestMaybeSubtractReservedNativeV2Plus(t *testing.T) { } func TestMaybeSubtractReservedNativeV2(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) lggr := logger.TestLogger(t) - cfg := pgtest.NewQConfig(false) - ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) - require.NoError(t, ks.Unlock("blah")) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) + require.NoError(t, ks.Unlock(ctx, "blah")) chainID := testutils.SimulatedChainID subID := new(big.Int).SetUint64(1) diff --git a/core/services/vrf/v2/listener_v2_types.go b/core/services/vrf/v2/listener_v2_types.go index f10297f31a9..c7dc45bb3bd 100644 --- a/core/services/vrf/v2/listener_v2_types.go +++ b/core/services/vrf/v2/listener_v2_types.go @@ -8,10 +8,10 @@ import ( "github.com/ethereum/go-ethereum/common" heaps "github.com/theodesp/go-heaps" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" ) @@ -222,8 +222,8 @@ func (lsn *listenerV2) processBatch( ) ll.Info("Enqueuing batch fulfillment") var ethTX txmgr.Tx - err = lsn.q.Transaction(func(tx pg.Queryer) error { - if err = lsn.pipelineRunner.InsertFinishedRuns(batch.runs, true, pg.WithQueryer(tx)); err != nil { + err = sqlutil.TransactDataSource(ctx, lsn.ds, nil, func(tx sqlutil.DataSource) error { + if err = lsn.pipelineRunner.InsertFinishedRuns(ctx, tx, batch.runs, true); err != nil { return fmt.Errorf("inserting finished pipeline runs: %w", err) } diff --git a/core/services/vrf/v2/reverted_txns.go b/core/services/vrf/v2/reverted_txns.go index d2f62fbf271..cfd9954a208 100644 --- a/core/services/vrf/v2/reverted_txns.go +++ b/core/services/vrf/v2/reverted_txns.go @@ -17,13 +17,13 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -71,15 +71,15 @@ func (lsn *listenerV2) handleRevertedTxns(ctx context.Context, pollPeriod time.D lsn.l.Infow("Handling reverted txns") // Fetch recent single and batch txns, that have not been force-fulfilled - recentSingleTxns, err := lsn.fetchRecentSingleTxns(ctx, lsn.q, lsn.chainID.Uint64(), pollPeriod) + recentSingleTxns, err := lsn.fetchRecentSingleTxns(ctx, lsn.ds, lsn.chainID.Uint64(), pollPeriod) if err != nil { lsn.l.Fatalw("Fetch recent txns", "err", err) } - recentBatchTxns, err := lsn.fetchRecentBatchTxns(ctx, lsn.q, lsn.chainID.Uint64(), pollPeriod) + recentBatchTxns, err := lsn.fetchRecentBatchTxns(ctx, lsn.ds, lsn.chainID.Uint64(), pollPeriod) if err != nil { lsn.l.Fatalw("Fetch recent batch txns", "err", err) } - recentForceFulfillmentTxns, err := lsn.fetchRevertedForceFulfilmentTxns(ctx, lsn.q, lsn.chainID.Uint64(), pollPeriod) + recentForceFulfillmentTxns, err := lsn.fetchRevertedForceFulfilmentTxns(ctx, lsn.ds, lsn.chainID.Uint64(), pollPeriod) if err != nil { lsn.l.Fatalw("Fetch recent reverted force-fulfillment txns", "err", err) } @@ -108,7 +108,7 @@ func (lsn *listenerV2) handleRevertedTxns(ctx context.Context, pollPeriod time.D } func (lsn *listenerV2) fetchRecentSingleTxns(ctx context.Context, - q pg.Q, + ds sqlutil.DataSource, chainID uint64, pollPeriod time.Duration) ([]TxnReceiptDB, error) { @@ -155,7 +155,7 @@ func (lsn *listenerV2) fetchRecentSingleTxns(ctx context.Context, var recentReceipts []TxnReceiptDB before := time.Now() - err := q.Select(&recentReceipts, sqlQuery, chainID) + err := ds.SelectContext(ctx, &recentReceipts, sqlQuery, chainID) lsn.postSqlLog(ctx, before, pollPeriod, "FetchRecentSingleTxns") if err != nil && !errors.Is(err, sql.ErrNoRows) { return nil, errors.Wrap(err, "Error fetching recent non-force-fulfilled txns") @@ -172,7 +172,7 @@ func (lsn *listenerV2) fetchRecentSingleTxns(ctx context.Context, } func (lsn *listenerV2) fetchRecentBatchTxns(ctx context.Context, - q pg.Q, + ds sqlutil.DataSource, chainID uint64, pollPeriod time.Duration) ([]TxnReceiptDB, error) { sqlQuery := fmt.Sprintf(` @@ -217,7 +217,7 @@ func (lsn *listenerV2) fetchRecentBatchTxns(ctx context.Context, var recentReceipts []TxnReceiptDB before := time.Now() - err := q.Select(&recentReceipts, sqlQuery, chainID) + err := ds.SelectContext(ctx, &recentReceipts, sqlQuery, chainID) lsn.postSqlLog(ctx, before, pollPeriod, "FetchRecentBatchTxns") if err != nil && !errors.Is(err, sql.ErrNoRows) { return nil, errors.Wrap(err, "Error fetching recent non-force-fulfilled txns") @@ -231,7 +231,7 @@ func (lsn *listenerV2) fetchRecentBatchTxns(ctx context.Context, } func (lsn *listenerV2) fetchRevertedForceFulfilmentTxns(ctx context.Context, - q pg.Q, + ds sqlutil.DataSource, chainID uint64, pollPeriod time.Duration) ([]TxnReceiptDB, error) { @@ -271,7 +271,7 @@ func (lsn *listenerV2) fetchRevertedForceFulfilmentTxns(ctx context.Context, var recentReceipts []TxnReceiptDB before := time.Now() - err := q.Select(&recentReceipts, sqlQuery, chainID) + err := ds.SelectContext(ctx, &recentReceipts, sqlQuery, chainID) lsn.postSqlLog(ctx, before, pollPeriod, "FetchRevertedForceFulfilmentTxns") if err != nil && !errors.Is(err, sql.ErrNoRows) { return nil, errors.Wrap(err, "Error fetching recent reverted force-fulfilled txns") @@ -300,7 +300,7 @@ func (lsn *listenerV2) fetchRevertedForceFulfilmentTxns(ctx context.Context, `, ReqScanTimeRangeInDB) var allReceipts []TxnReceiptDB before = time.Now() - err = q.Select(&allReceipts, sqlQueryAll, chainID) + err = ds.SelectContext(ctx, &allReceipts, sqlQueryAll, chainID) lsn.postSqlLog(ctx, before, pollPeriod, "Fetch all ForceFulfilment Txns") if err != nil && !errors.Is(err, sql.ErrNoRows) { return nil, errors.Wrap(err, "Error fetching all recent force-fulfilled txns") @@ -389,9 +389,10 @@ func (lsn *listenerV2) postSqlLog(ctx context.Context, begin time.Time, pollPeri lsn.l.Debugw("SQL context canceled", "ms", elapsed.Milliseconds(), "err", ctx.Err(), "sql", queryName) } - timeout := lsn.q.QueryTimeout - if timeout <= 0 { - timeout = pollPeriod + timeout := pollPeriod + deadline, ok := ctx.Deadline() + if ok { + timeout = deadline.Sub(begin) } pct := float64(elapsed) / float64(timeout) diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index 0c08e992f32..690ae38d088 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -74,7 +73,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) { ) } } -func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.ServiceCtx, error) { diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index 010b6f8db0a..9711ae686ea 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/webhook/mocks/http_client.go b/core/services/webhook/mocks/http_client.go index fa4f597dc4f..27167f235c3 100644 --- a/core/services/webhook/mocks/http_client.go +++ b/core/services/webhook/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/services/workflows/delegate.go b/core/services/workflows/delegate.go index 6db39d52dd6..e22a78212d2 100644 --- a/core/services/workflows/delegate.go +++ b/core/services/workflows/delegate.go @@ -3,23 +3,19 @@ package workflows import ( "context" "fmt" - "time" "github.com/google/uuid" "github.com/pelletier/go-toml" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/mercury" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type Delegate struct { - registry types.CapabilitiesRegistry + registry core.CapabilitiesRegistry logger logger.Logger legacyEVMChains legacyevm.LegacyChainContainer } @@ -36,7 +32,7 @@ func (d *Delegate) AfterJobCreated(jb job.Job) {} func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) error { return nil } +func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.ServiceCtx, error) { @@ -46,14 +42,6 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.Ser d.logger.Errorw("could not initialize writes", err) } - trigger := triggers.NewMercuryTriggerService(0, d.logger) - err = d.registry.Add(context.Background(), trigger) - if err != nil { - d.logger.Errorw("could not add mercury trigger to registry", err) - } else { - go mercuryEventLoop(trigger, d.logger) - } - cfg := Config{ Lggr: d.logger, Spec: spec.WorkflowSpec.Workflow, @@ -67,56 +55,10 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.Ser return []job.ServiceCtx{engine}, nil } -func NewDelegate(logger logger.Logger, registry types.CapabilitiesRegistry, legacyEVMChains legacyevm.LegacyChainContainer) *Delegate { +func NewDelegate(logger logger.Logger, registry core.CapabilitiesRegistry, legacyEVMChains legacyevm.LegacyChainContainer) *Delegate { return &Delegate{logger: logger, registry: registry, legacyEVMChains: legacyEVMChains} } -func mercuryEventLoop(trigger *triggers.MercuryTriggerService, logger logger.Logger) { - sleepSec := 60 * time.Second - ticker := time.NewTicker(sleepSec) - defer ticker.Stop() - - prices := []int64{300000, 2000, 5000000} - - for range ticker.C { - for i := range prices { - prices[i] = prices[i] + 1 - } - - t := time.Now().Round(sleepSec).Unix() - reports, err := emitReports(logger, trigger, t, prices) - if err != nil { - logger.Errorw("failed to process Mercury reports", "err", err, "timestamp", time.Now().Unix(), "payload", reports) - } - } -} - -func emitReports(logger logger.Logger, trigger *triggers.MercuryTriggerService, t int64, prices []int64) ([]mercury.FeedReport, error) { - reports := []mercury.FeedReport{ - { - FeedID: "0x1111111111111111111100000000000000000000000000000000000000000000", - FullReport: []byte(fmt.Sprintf(`{ "feed": "ETH", "price": %d }`, prices[0])), - BenchmarkPrice: prices[0], - ObservationTimestamp: t, - }, - { - FeedID: "0x2222222222222222222200000000000000000000000000000000000000000000", - FullReport: []byte(fmt.Sprintf(`{ "feed": "LINK", "price": %d }`, prices[1])), - BenchmarkPrice: prices[1], - ObservationTimestamp: t, - }, - { - FeedID: "0x3333333333333333333300000000000000000000000000000000000000000000", - FullReport: []byte(fmt.Sprintf(`{ "feed": "BTC", "price": %d }`, prices[2])), - BenchmarkPrice: prices[2], - ObservationTimestamp: t, - }, - } - - logger.Infow("New set of Mercury reports", "timestamp", time.Now().Unix(), "payload", reports) - return reports, trigger.ProcessReport(reports) -} - func ValidatedWorkflowSpec(tomlString string) (job.Job, error) { var jb = job.Job{ExternalJobID: uuid.New()} diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index f6b8c63ed15..052c2c86647 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -25,7 +25,7 @@ const ( type Engine struct { services.StateMachine logger logger.Logger - registry types.CapabilitiesRegistry + registry core.CapabilitiesRegistry workflow *workflow executionStates *inMemoryStore pendingStepRequests chan stepRequest @@ -183,10 +183,17 @@ func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability) erro Config: tc, Inputs: triggerInputs, } - err = t.trigger.RegisterTrigger(ctx, e.triggerEvents, triggerRegRequest) + eventsCh, err := t.trigger.RegisterTrigger(ctx, triggerRegRequest) if err != nil { return fmt.Errorf("failed to instantiate trigger %s, %s", t.Type, err) } + + go func() { + for event := range eventsCh { + e.triggerEvents <- event + } + }() + return nil } @@ -212,7 +219,12 @@ func (e *Engine) loop(ctx context.Context) { case <-ctx.Done(): e.logger.Debugw("shutting down loop") return - case resp := <-e.triggerEvents: + case resp, isOpen := <-e.triggerEvents: + if !isOpen { + e.logger.Errorf("trigger events channel is no longer open, skipping") + continue + } + if resp.Err != nil { e.logger.Errorf("trigger event was an error; not executing", resp.Err) continue @@ -579,7 +591,7 @@ type Config struct { Spec string WorkflowID string Lggr logger.Logger - Registry types.CapabilitiesRegistry + Registry core.CapabilitiesRegistry MaxWorkerLimit int QueueSize int NewWorkerTimeout time.Duration diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 7632bbb7a27..7bb6cd00c1c 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -79,16 +79,18 @@ func newMockCapability(info capabilities.CapabilityInfo, transform func(capabili } } -func (m *mockCapability) Execute(ctx context.Context, ch chan<- capabilities.CapabilityResponse, req capabilities.CapabilityRequest) error { +func (m *mockCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { cr, err := m.transform(req) if err != nil { - return err + return nil, err } + ch := make(chan capabilities.CapabilityResponse, 10) + + m.response <- cr ch <- cr close(ch) - m.response <- cr - return nil + return ch, nil } func (m *mockCapability) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { @@ -102,13 +104,14 @@ func (m *mockCapability) UnregisterFromWorkflow(ctx context.Context, request cap type mockTriggerCapability struct { capabilities.CapabilityInfo triggerEvent capabilities.CapabilityResponse + ch chan capabilities.CapabilityResponse } var _ capabilities.TriggerCapability = (*mockTriggerCapability)(nil) -func (m *mockTriggerCapability) RegisterTrigger(ctx context.Context, ch chan<- capabilities.CapabilityResponse, req capabilities.CapabilityRequest) error { - ch <- m.triggerEvent - return nil +func (m *mockTriggerCapability) RegisterTrigger(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { + m.ch <- m.triggerEvent + return m.ch, nil } func (m *mockTriggerCapability) UnregisterTrigger(ctx context.Context, req capabilities.CapabilityRequest) error { @@ -116,6 +119,7 @@ func (m *mockTriggerCapability) UnregisterTrigger(ctx context.Context, req capab } func TestEngineWithHardcodedWorkflow(t *testing.T) { + t.Parallel() ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) @@ -216,6 +220,7 @@ func mockTrigger(t *testing.T) (capabilities.TriggerCapability, capabilities.Cap "issues a trigger when a mercury report is received.", "v1.0.0", ), + ch: make(chan capabilities.CapabilityResponse, 10), } resp, err := values.NewMap(map[string]any{ "123": decimal.NewFromFloat(1.00), @@ -288,6 +293,7 @@ func mockTarget() *mockCapability { } func TestEngine_ErrorsTheWorkflowIfAStepErrors(t *testing.T) { + t.Parallel() ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) @@ -388,6 +394,7 @@ func mockAction() (*mockCapability, values.Value) { } func TestEngine_MultiStepDependencies(t *testing.T) { + t.Parallel() ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) diff --git a/core/services/workflows/models_test.go b/core/services/workflows/models_test.go index 61aced2ed19..232e91eaaa8 100644 --- a/core/services/workflows/models_test.go +++ b/core/services/workflows/models_test.go @@ -8,6 +8,7 @@ import ( ) func TestParse_Graph(t *testing.T) { + t.Parallel() testCases := []struct { name string yaml string diff --git a/core/services/workflows/models_yaml_test.go b/core/services/workflows/models_yaml_test.go index 411781a3782..2732f1b44c7 100644 --- a/core/services/workflows/models_yaml_test.go +++ b/core/services/workflows/models_yaml_test.go @@ -52,6 +52,7 @@ var transformJSON = cmp.FilterValues(func(x, y []byte) bool { })) func TestWorkflowSpecMarshalling(t *testing.T) { + t.Parallel() fixtureReader := yamlFixtureReaderBytes(t, "marshalling") t.Run("Type coercion", func(t *testing.T) { @@ -168,6 +169,7 @@ func TestWorkflowSpecMarshalling(t *testing.T) { } func TestJsonSchema(t *testing.T) { + t.Parallel() t.Run("GenerateJsonSchema", func(t *testing.T) { expectedSchemaPath := fixtureDir + "workflow_schema.json" generatedSchema, err := GenerateJsonSchema() diff --git a/core/services/workflows/state_test.go b/core/services/workflows/state_test.go index 9e69520c242..0917662ccb6 100644 --- a/core/services/workflows/state_test.go +++ b/core/services/workflows/state_test.go @@ -11,6 +11,7 @@ import ( ) func TestInterpolateKey(t *testing.T) { + t.Parallel() val, err := values.NewMap( map[string]any{ "reports": map[string]any{ @@ -202,6 +203,7 @@ func TestInterpolateKey(t *testing.T) { } func TestInterpolateInputsFromState(t *testing.T) { + t.Parallel() testCases := []struct { name string inputs map[string]any diff --git a/core/sessions/ldapauth/mocks/ldap_client.go b/core/sessions/ldapauth/mocks/ldap_client.go index 63021636018..d8fe4dbadfc 100644 --- a/core/sessions/ldapauth/mocks/ldap_client.go +++ b/core/sessions/ldapauth/mocks/ldap_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/sessions/ldapauth/mocks/ldap_conn.go b/core/sessions/ldapauth/mocks/ldap_conn.go index 8b4fff82047..3116320cd99 100644 --- a/core/sessions/ldapauth/mocks/ldap_conn.go +++ b/core/sessions/ldapauth/mocks/ldap_conn.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/sessions/mocks/authentication_provider.go b/core/sessions/mocks/authentication_provider.go index 82be3a578d0..3031a7c9809 100644 --- a/core/sessions/mocks/authentication_provider.go +++ b/core/sessions/mocks/authentication_provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/sessions/mocks/basic_admin_users_orm.go b/core/sessions/mocks/basic_admin_users_orm.go index dc9c40a62c0..b8376267c24 100644 --- a/core/sessions/mocks/basic_admin_users_orm.go +++ b/core/sessions/mocks/basic_admin_users_orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.42.2. DO NOT EDIT. package mocks diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 286e1b3a295..3c0c2dc2158 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -27,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/migrate" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -37,7 +36,7 @@ var migrationDir = "migrations" type OffchainReporting2OracleSpec100 struct { ID int32 `toml:"-"` ContractID string `toml:"contractID"` - Relay relay.Network `toml:"relay"` + Relay string `toml:"relay"` // RelayID.Network RelayConfig job.JSONConfig `toml:"relayConfig"` P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers"` OCRKeyBundleID null.String `toml:"ocrKeyBundleID"` @@ -78,14 +77,15 @@ func TestMigrate_0100_BootstrapConfigs(t *testing.T) { err := goose.UpTo(db.DB, migrationDir, 99) require.NoError(t, err) - pipelineORM := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) - pipelineID, err := pipelineORM.CreateSpec(pipeline.Pipeline{}, 0) + pipelineORM := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) + ctx := testutils.Context(t) + pipelineID, err := pipelineORM.CreateSpec(ctx, nil, pipeline.Pipeline{}, 0) require.NoError(t, err) - pipelineID2, err := pipelineORM.CreateSpec(pipeline.Pipeline{}, 0) + pipelineID2, err := pipelineORM.CreateSpec(ctx, nil, pipeline.Pipeline{}, 0) require.NoError(t, err) - nonBootstrapPipelineID, err := pipelineORM.CreateSpec(pipeline.Pipeline{}, 0) + nonBootstrapPipelineID, err := pipelineORM.CreateSpec(ctx, nil, pipeline.Pipeline{}, 0) require.NoError(t, err) - newFormatBoostrapPipelineID2, err := pipelineORM.CreateSpec(pipeline.Pipeline{}, 0) + newFormatBoostrapPipelineID2, err := pipelineORM.CreateSpec(ctx, nil, pipeline.Pipeline{}, 0) require.NoError(t, err) // OCR2 struct at migration v0099 diff --git a/core/web/build_info_controller_test.go b/core/web/build_info_controller_test.go index 5a2b88fa0dc..05ae421bf23 100644 --- a/core/web/build_info_controller_test.go +++ b/core/web/build_info_controller_test.go @@ -5,18 +5,19 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" clhttptest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/httptest" - - "github.com/stretchr/testify/require" ) func TestBuildInfoController_Show_APICredentials(t *testing.T) { t.Parallel() app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) @@ -32,8 +33,8 @@ func TestBuildInfoController_Show_APICredentials(t *testing.T) { func TestBuildInfoController_Show_NoCredentials(t *testing.T) { t.Parallel() - ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) + ctx := testutils.Context(t) require.NoError(t, app.Start(ctx)) client := clhttptest.NewTestLocalOnlyHTTPClient() diff --git a/core/web/chains_controller.go b/core/web/chains_controller.go index 61c8d1dc84d..bcaaf909540 100644 --- a/core/web/chains_controller.go +++ b/core/web/chains_controller.go @@ -12,7 +12,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type ChainsController interface { @@ -23,7 +22,7 @@ type ChainsController interface { } type chainsController[R jsonapi.EntityNamer] struct { - network relay.Network + network string resourceName string chainStats chainlink.ChainStatuser errNotEnabled error @@ -41,7 +40,7 @@ func (e errChainDisabled) Error() string { return fmt.Sprintf("%s is disabled: Set %s=true to enable", e.name, e.tomlKey) } -func newChainsController[R jsonapi.EntityNamer](network relay.Network, chainStats chainlink.ChainsNodesStatuser, errNotEnabled error, +func newChainsController[R jsonapi.EntityNamer](network string, chainStats chainlink.ChainsNodesStatuser, errNotEnabled error, newResource func(types.ChainStatus) R, lggr logger.Logger, auditLogger audit.AuditLogger) *chainsController[R] { return &chainsController[R]{ network: network, @@ -79,7 +78,7 @@ func (cc *chainsController[R]) Show(c *gin.Context) { jsonAPIError(c, http.StatusBadRequest, cc.errNotEnabled) return } - relayID := relay.ID{Network: cc.network, ChainID: c.Param("ID")} + relayID := types.RelayID{Network: cc.network, ChainID: c.Param("ID")} chain, err := cc.chainStats.ChainStatus(c, relayID) if err != nil { jsonAPIError(c, http.StatusBadRequest, err) diff --git a/core/web/cosmos_chains_controller.go b/core/web/cosmos_chains_controller.go index 20a0738c5eb..56ae007128f 100644 --- a/core/web/cosmos_chains_controller.go +++ b/core/web/cosmos_chains_controller.go @@ -1,15 +1,15 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) func NewCosmosChainsController(app chainlink.Application) ChainsController { return newChainsController[presenters.CosmosChainResource]( - relay.Cosmos, - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.Cosmos)), + types.NetworkCosmos, + app.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkCosmos)), ErrCosmosNotEnabled, presenters.NewCosmosChainResource, app.GetLogger(), diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index 5491b33c359..9aaa0dd9eeb 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -182,7 +182,8 @@ func setupCosmosChainsControllerTestV2(t *testing.T, cfgs ...*coscfg.TOMLConfig) c.EVM = nil }) app := cltest.NewApplicationWithConfig(t, cfg) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) diff --git a/core/web/cosmos_keys_controller_test.go b/core/web/cosmos_keys_controller_test.go index 3b777de7b7c..1de64625dfa 100644 --- a/core/web/cosmos_keys_controller_test.go +++ b/core/web/cosmos_keys_controller_test.go @@ -40,7 +40,8 @@ func TestCosmosKeysController_Create_HappyPath(t *testing.T) { t.Parallel() app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) keyStore := app.GetKeyStore() @@ -75,12 +76,13 @@ func TestCosmosKeysController_Delete_NonExistentCosmosKeyID(t *testing.T) { func TestCosmosKeysController_Delete_HappyPath(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client, keyStore := setupCosmosKeysControllerTests(t) keys, _ := keyStore.Cosmos().GetAll() initialLength := len(keys) - key, _ := keyStore.Cosmos().Create() + key, _ := keyStore.Cosmos().Create(ctx) response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/cosmos/%s", key.ID())) t.Cleanup(cleanup) @@ -93,10 +95,11 @@ func TestCosmosKeysController_Delete_HappyPath(t *testing.T) { func setupCosmosKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { t.Helper() + ctx := testutils.Context(t) app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.Cosmos().Add(cltest.DefaultCosmosKey)) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.Cosmos().Add(ctx, cltest.DefaultCosmosKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/cosmos_nodes_controller.go b/core/web/cosmos_nodes_controller.go index 121d7d8422b..c384c10247f 100644 --- a/core/web/cosmos_nodes_controller.go +++ b/core/web/cosmos_nodes_controller.go @@ -1,8 +1,8 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -10,7 +10,7 @@ import ( var ErrCosmosNotEnabled = errChainDisabled{name: "Cosmos", tomlKey: "Cosmos.Enabled"} func NewCosmosNodesController(app chainlink.Application) NodesController { - scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.Cosmos) + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), types.NetworkCosmos) return newNodesController[presenters.CosmosNodeResource]( scopedNodeStatuser, ErrCosmosNotEnabled, presenters.NewCosmosNodeResource, app.GetAuditLogger(), diff --git a/core/web/cosmos_transfer_controller.go b/core/web/cosmos_transfer_controller.go index 9b958346642..d0de1fd727e 100644 --- a/core/web/cosmos_transfer_controller.go +++ b/core/web/cosmos_transfer_controller.go @@ -10,10 +10,10 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/types" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/denom" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -28,7 +28,7 @@ type CosmosTransfersController struct { // Create sends native coins from the Chainlink's account to a specified address. func (tc *CosmosTransfersController) Create(c *gin.Context) { - relayers := tc.App.GetRelayers().List(chainlink.FilterRelayersByType(relay.Cosmos)) + relayers := tc.App.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkCosmos)) if relayers == nil { jsonAPIError(c, http.StatusBadRequest, ErrSolanaNotEnabled) return @@ -48,7 +48,7 @@ func (tc *CosmosTransfersController) Create(c *gin.Context) { return } - relayerID := relay.ID{Network: relay.Cosmos, ChainID: tr.CosmosChainID} + relayerID := types.RelayID{Network: types.NetworkCosmos, ChainID: tr.CosmosChainID} relayer, err := relayers.Get(relayerID) if err != nil { if errors.Is(err, chainlink.ErrNoSuchRelayer) { diff --git a/core/web/csa_keys_controller.go b/core/web/csa_keys_controller.go index fc927c61b3c..f97e5751df0 100644 --- a/core/web/csa_keys_controller.go +++ b/core/web/csa_keys_controller.go @@ -34,7 +34,8 @@ func (ctrl *CSAKeysController) Index(c *gin.Context) { // Example: // "POST /keys/csa" func (ctrl *CSAKeysController) Create(c *gin.Context) { - key, err := ctrl.App.GetKeyStore().CSA().Create() + ctx := c.Request.Context() + key, err := ctrl.App.GetKeyStore().CSA().Create(ctx) if err != nil { if errors.Is(err, keystore.ErrCSAKeyExists) { jsonAPIError(c, http.StatusBadRequest, err) @@ -56,6 +57,7 @@ func (ctrl *CSAKeysController) Create(c *gin.Context) { // Import imports a CSA key func (ctrl *CSAKeysController) Import(c *gin.Context) { defer ctrl.App.GetLogger().ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -63,7 +65,7 @@ func (ctrl *CSAKeysController) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - key, err := ctrl.App.GetKeyStore().CSA().Import(bytes, oldPassword) + key, err := ctrl.App.GetKeyStore().CSA().Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/dkgencrypt_keys_controller_test.go b/core/web/dkgencrypt_keys_controller_test.go index 7100cbbb1cd..fde00eb6420 100644 --- a/core/web/dkgencrypt_keys_controller_test.go +++ b/core/web/dkgencrypt_keys_controller_test.go @@ -100,8 +100,9 @@ func setupDKGEncryptKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, t.Helper() app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.DKGEncrypt().Add(cltest.DefaultDKGEncryptKey)) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.DKGEncrypt().Add(ctx, cltest.DefaultDKGEncryptKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/dkgsign_keys_controller_test.go b/core/web/dkgsign_keys_controller_test.go index ed67d71a0d5..b253a36ccc3 100644 --- a/core/web/dkgsign_keys_controller_test.go +++ b/core/web/dkgsign_keys_controller_test.go @@ -100,8 +100,9 @@ func setupDKGSignKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, ke t.Helper() app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.DKGSign().Add(cltest.DefaultDKGSignKey)) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.DKGSign().Add(ctx, cltest.DefaultDKGSignKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index bab987fbcc2..09a3eb5fa1e 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -30,6 +30,7 @@ import ( func TestETHKeysController_Index_Success(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -39,7 +40,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled key k0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -55,7 +56,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { ethClient.On("LINKBalance", mock.Anything, addr1, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr2, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/evm") @@ -83,6 +84,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { func TestETHKeysController_Index_Errors(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -92,14 +94,14 @@ func TestETHKeysController_Index_Errors(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") @@ -121,6 +123,7 @@ func TestETHKeysController_Index_Errors(t *testing.T) { func TestETHKeysController_Index_Disabled(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -129,11 +132,11 @@ func TestETHKeysController_Index_Disabled(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") @@ -168,7 +171,8 @@ func TestETHKeysController_Index_NotDev(t *testing.T) { ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(256), nil).Once() app := cltest.NewApplicationWithConfigAndKey(t, cfg, ethClient) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") @@ -193,7 +197,8 @@ func TestETHKeysController_Index_NoAccounts(t *testing.T) { t.Parallel() app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) @@ -227,7 +232,8 @@ func TestETHKeysController_CreateSuccess(t *testing.T) { client := app.NewHTTPClient(nil) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) chainURL := url.URL{Path: "/v2/keys/evm"} query := chainURL.Query() @@ -250,6 +256,7 @@ func TestETHKeysController_CreateSuccess(t *testing.T) { func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -258,7 +265,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled key key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -266,7 +273,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -292,6 +299,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -301,7 +309,7 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled key key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -309,7 +317,7 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -337,6 +345,7 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -345,7 +354,7 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // disabled key key, addr := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) @@ -353,7 +362,7 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -381,6 +390,7 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -390,7 +400,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled key key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -398,7 +408,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) chain := app.GetRelayers().LegacyEVMChains().Slice()[0] subject := uuid.New() @@ -454,6 +464,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -466,9 +477,9 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { // enabled key _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -487,6 +498,7 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -499,9 +511,9 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { // enabled key _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -520,6 +532,7 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { func TestETHKeysController_ChainFailure_InvalidAddress(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -528,9 +541,9 @@ func TestETHKeysController_ChainFailure_InvalidAddress(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -548,6 +561,7 @@ func TestETHKeysController_ChainFailure_InvalidAddress(t *testing.T) { func TestETHKeysController_ChainFailure_MissingAddress(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -556,9 +570,9 @@ func TestETHKeysController_ChainFailure_MissingAddress(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -576,6 +590,7 @@ func TestETHKeysController_ChainFailure_MissingAddress(t *testing.T) { func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -584,9 +599,9 @@ func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -604,6 +619,7 @@ func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) @@ -613,12 +629,12 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled key _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -636,6 +652,7 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { func TestETHKeysController_DeleteSuccess(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -643,7 +660,7 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) // enabled keys key0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -654,7 +671,7 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { ethClient.On("LINKBalance", mock.Anything, addr0, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr1, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/" + addr0.Hex()} @@ -688,15 +705,16 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { func TestETHKeysController_DeleteFailure_InvalidAddress(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm" + "/bad_address"} @@ -709,15 +727,16 @@ func TestETHKeysController_DeleteFailure_InvalidAddress(t *testing.T) { func TestETHKeysController_DeleteFailure_KeyMissing(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) + require.NoError(t, app.KeyStore.Unlock(ctx, cltest.Password)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/" + testutils.NewAddress().Hex()} diff --git a/core/web/evm_chains_controller.go b/core/web/evm_chains_controller.go index 45b4964c215..3d939a9f9bc 100644 --- a/core/web/evm_chains_controller.go +++ b/core/web/evm_chains_controller.go @@ -1,8 +1,8 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -10,8 +10,8 @@ var ErrEVMNotEnabled = errChainDisabled{name: "EVM", tomlKey: "EVM.Enabled"} func NewEVMChainsController(app chainlink.Application) ChainsController { return newChainsController[presenters.EVMChainResource]( - relay.EVM, - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.EVM)), + types.NetworkEVM, + app.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkEVM)), ErrEVMNotEnabled, presenters.NewEVMChainResource, app.GetLogger(), diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index 5d31374cfb7..157978bdd46 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -202,7 +202,8 @@ func setupEVMChainsControllerTest(t *testing.T, cfg chainlink.GeneralConfig) *Te // Using this instead of `NewApplicationEVMDisabled` since we need the chain set to be loaded in the app // for the sake of the API endpoints to work properly app := cltest.NewApplicationWithConfig(t, cfg) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) diff --git a/core/web/evm_forwarders_controller_test.go b/core/web/evm_forwarders_controller_test.go index 031a1a61c03..38e8c2f91f0 100644 --- a/core/web/evm_forwarders_controller_test.go +++ b/core/web/evm_forwarders_controller_test.go @@ -30,7 +30,8 @@ func setupEVMForwardersControllerTest(t *testing.T, overrideFn func(c *chainlink // Using this instead of `NewApplicationEVMDisabled` since we need the chain set to be loaded in the app // for the sake of the API endpoints to work properly app := cltest.NewApplicationWithConfig(t, configtest.NewGeneralConfig(t, overrideFn)) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) diff --git a/core/web/evm_nodes_controller.go b/core/web/evm_nodes_controller.go index c8d0b91c0f7..ba8e112c365 100644 --- a/core/web/evm_nodes_controller.go +++ b/core/web/evm_nodes_controller.go @@ -1,13 +1,13 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) func NewEVMNodesController(app chainlink.Application) NodesController { - scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.EVM) + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), types.NetworkEVM) return newNodesController[presenters.EVMNodeResource]( scopedNodeStatuser, ErrEVMNotEnabled, presenters.NewEVMNodeResource, app.GetAuditLogger()) diff --git a/core/web/evm_transactions_controller_test.go b/core/web/evm_transactions_controller_test.go index e6d186fbab3..a4dd21c9f03 100644 --- a/core/web/evm_transactions_controller_test.go +++ b/core/web/evm_transactions_controller_test.go @@ -22,12 +22,12 @@ func TestTransactionsController_Index_Success(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithKey(t) - require.NoError(t, app.Start(testutils.Context(t))) ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) db := app.GetSqlxDB() txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) - ethKeyStore := cltest.NewKeyStore(t, db, app.Config.Database()).Eth() + ethKeyStore := cltest.NewKeyStore(t, db).Eth() client := app.NewHTTPClient(nil) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -68,7 +68,8 @@ func TestTransactionsController_Index_Error(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithKey(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/transactions?size=TrainingDay") @@ -80,7 +81,8 @@ func TestTransactionsController_Show_Success(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithKey(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) client := app.NewHTTPClient(nil) @@ -113,7 +115,8 @@ func TestTransactionsController_Show_NotFound(t *testing.T) { t.Parallel() app := cltest.NewApplicationWithKey(t) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) client := app.NewHTTPClient(nil) diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 5226d7dd7d6..0808422cca7 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -222,7 +222,7 @@ func (jc *JobsController) validateJobSpec(ctx context.Context, tomlString string config := jc.App.GetConfig() switch jobType { case job.OffchainReporting: - jb, err = ocr.ValidatedOracleSpecToml(jc.App.GetRelayers().LegacyEVMChains(), tomlString) + jb, err = ocr.ValidatedOracleSpecToml(config, jc.App.GetRelayers().LegacyEVMChains(), tomlString) if !config.OCR().Enabled() { return jb, http.StatusNotImplemented, errors.New("The Offchain Reporting feature is disabled by configuration") } diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 5255cad75f3..9c7b529b6bf 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -77,6 +77,7 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { + ctx := testutils.Context(t) ta, client := setupJobsControllerTests(t) var address types.EIP55Address @@ -87,7 +88,7 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin address = cltest.NewEIP55Address() } - require.NoError(t, ta.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, ta.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) sp := cltest.MinimalOCRNonBootstrapSpec(contractAddress, address, tc.pid, tc.kb) body, _ := json.Marshal(web.CreateJobRequest{ @@ -104,8 +105,9 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin } func TestJobController_Create_DirectRequest_Fast(t *testing.T) { + ctx := testutils.Context(t) app, client := setupJobsControllerTests(t) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) n := 10 @@ -137,9 +139,10 @@ func mustInt32FromString(t *testing.T, s string) int32 { } func TestJobController_Create_HappyPath(t *testing.T) { + ctx := testutils.Context(t) app, client := setupJobsControllerTests(t) b1, b2 := setupBridges(t, app.GetSqlxDB(), app.GetConfig().Database()) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) var pks []vrfkey.KeyV2 var k []p2pkey.KeyV2 { @@ -477,7 +480,6 @@ targets: func TestJobsController_Create_WebhookSpec(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, app.Stop()) }) _, fetchBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) _, submitBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) @@ -608,6 +610,7 @@ func TestJobsController_Show_NonExistentID(t *testing.T) { } func TestJobsController_Update_HappyPath(t *testing.T) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V2.Enabled = ptr(true) @@ -616,7 +619,7 @@ func TestJobsController_Update_HappyPath(t *testing.T) { }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) require.NoError(t, app.Start(testutils.Context(t))) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) @@ -680,7 +683,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) @@ -766,11 +769,12 @@ func setupJobsControllerTests(t *testing.T) (ta *cltest.TestApplication, cc clte }) ec := setupEthClientForControllerTests(t) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey, ec) - require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) + require.NoError(t, app.Start(ctx)) client := app.NewHTTPClient(nil) vrfKeyStore := app.GetKeyStore().VRF() - _, err := vrfKeyStore.Create() + _, err := vrfKeyStore.Create(ctx) require.NoError(t, err) return app, client } @@ -793,7 +797,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}) diff --git a/core/web/keys_controller.go b/core/web/keys_controller.go index 66fd596e719..ca7ef5e134a 100644 --- a/core/web/keys_controller.go +++ b/core/web/keys_controller.go @@ -1,6 +1,7 @@ package web import ( + "context" "fmt" "io" "net/http" @@ -16,9 +17,9 @@ import ( type Keystore[K keystore.Key] interface { Get(id string) (K, error) GetAll() ([]K, error) - Create() (K, error) - Delete(id string) (K, error) - Import(keyJSON []byte, password string) (K, error) + Create(context.Context) (K, error) + Delete(ctx context.Context, id string) (K, error) + Import(ctx context.Context, keyJSON []byte, password string) (K, error) Export(id string, password string) ([]byte, error) } @@ -73,7 +74,8 @@ func (kc *keysController[K, R]) Index(c *gin.Context) { } func (kc *keysController[K, R]) Create(c *gin.Context) { - key, err := kc.ks.Create() + ctx := c.Request.Context() + key, err := kc.ks.Create(ctx) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -88,13 +90,14 @@ func (kc *keysController[K, R]) Create(c *gin.Context) { } func (kc *keysController[K, R]) Delete(c *gin.Context) { + ctx := c.Request.Context() keyID := c.Param("keyID") key, err := kc.ks.Get(keyID) if err != nil { jsonAPIError(c, http.StatusNotFound, err) return } - _, err = kc.ks.Delete(key.ID()) + _, err = kc.ks.Delete(ctx, key.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -110,6 +113,7 @@ func (kc *keysController[K, R]) Delete(c *gin.Context) { func (kc *keysController[K, R]) Import(c *gin.Context) { defer kc.lggr.ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -117,7 +121,7 @@ func (kc *keysController[K, R]) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - key, err := kc.ks.Import(bytes, oldPassword) + key, err := kc.ks.Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/loader/chain.go b/core/web/loader/chain.go index 34ca4bd5f82..215c643f3c5 100644 --- a/core/web/loader/chain.go +++ b/core/web/loader/chain.go @@ -9,7 +9,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type chainBatcher struct { @@ -20,7 +19,7 @@ func (b *chainBatcher) loadByIDs(ctx context.Context, keys dataloader.Keys) []*d // Create a map for remembering the order of keys passed in keyOrder := make(map[string]int, len(keys)) // Collect the keys to search for - var chainIDs []relay.ChainID + var chainIDs []string for ix, key := range keys { chainIDs = append(chainIDs, key.String()) keyOrder[key.String()] = ix diff --git a/core/web/loader/node.go b/core/web/loader/node.go index 3d229813101..e67f1fd4d41 100644 --- a/core/web/loader/node.go +++ b/core/web/loader/node.go @@ -8,7 +8,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type nodeBatcher struct { @@ -20,10 +19,10 @@ func (b *nodeBatcher) loadByChainIDs(ctx context.Context, keys dataloader.Keys) keyOrder := make(map[string]int, len(keys)) // Collect the keys to search for // note backward compatibility -- this only ever supported evm chains - evmrelayIDs := make([]relay.ID, 0, len(keys)) + evmrelayIDs := make([]types.RelayID, 0, len(keys)) for ix, key := range keys { - rid := relay.ID{Network: relay.EVM, ChainID: key.String()} + rid := types.RelayID{Network: types.NetworkEVM, ChainID: key.String()} evmrelayIDs = append(evmrelayIDs, rid) keyOrder[key.String()] = ix } diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 93eda32d0e8..f6c71faca50 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -62,6 +62,7 @@ func (m *mockLoopImpl) run() { } func TestLoopRegistry(t *testing.T) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V2.Enabled = ptr(true) @@ -80,7 +81,7 @@ func TestLoopRegistry(t *testing.T) { model.LabelSet{"__metrics_path__": model.LabelValue(expectedLooppEndPoint)}, } - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) require.NoError(t, app.Start(testutils.Context(t))) // register a mock loop diff --git a/core/web/nodes_controller.go b/core/web/nodes_controller.go index 04c4693983f..bf5bb0e65e1 100644 --- a/core/web/nodes_controller.go +++ b/core/web/nodes_controller.go @@ -11,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type NodesController interface { @@ -20,11 +19,11 @@ type NodesController interface { } type NetworkScopedNodeStatuser struct { - network relay.Network + network string relayers chainlink.RelayerChainInteroperators } -func NewNetworkScopedNodeStatuser(relayers chainlink.RelayerChainInteroperators, network relay.Network) *NetworkScopedNodeStatuser { +func NewNetworkScopedNodeStatuser(relayers chainlink.RelayerChainInteroperators, network string) *NetworkScopedNodeStatuser { scoped := relayers.List(chainlink.FilterRelayersByType(network)) return &NetworkScopedNodeStatuser{ network: network, @@ -32,7 +31,7 @@ func NewNetworkScopedNodeStatuser(relayers chainlink.RelayerChainInteroperators, } } -func (n *NetworkScopedNodeStatuser) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { +func (n *NetworkScopedNodeStatuser) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...types.RelayID) (nodes []types.NodeStatus, count int, err error) { return n.relayers.NodeStatuses(ctx, offset, limit, relayIDs...) } @@ -75,7 +74,7 @@ func (n *nodesController[R]) Index(c *gin.Context, size, page, offset int) { } else { // fetch nodes for chain ID // backward compatibility - var rid relay.ID + var rid types.RelayID err = rid.UnmarshalString(id) if err != nil { rid.ChainID = id diff --git a/core/web/ocr2_keys_controller.go b/core/web/ocr2_keys_controller.go index 22109e90cba..2c4fcd19203 100644 --- a/core/web/ocr2_keys_controller.go +++ b/core/web/ocr2_keys_controller.go @@ -34,8 +34,9 @@ func (ocr2kc *OCR2KeysController) Index(c *gin.Context) { // Example: // "POST /keys/ocr" func (ocr2kc *OCR2KeysController) Create(c *gin.Context) { + ctx := c.Request.Context() chainType := chaintype.ChainType(c.Param("chainType")) - key, err := ocr2kc.App.GetKeyStore().OCR2().Create(chainType) + key, err := ocr2kc.App.GetKeyStore().OCR2().Create(ctx, chainType) if errors.Is(errors.Cause(err), chaintype.ErrInvalidChainType) { jsonAPIError(c, http.StatusBadRequest, err) return @@ -60,13 +61,14 @@ func (ocr2kc *OCR2KeysController) Create(c *gin.Context) { // Example: // "DELETE /keys/ocr/:keyID" func (ocr2kc *OCR2KeysController) Delete(c *gin.Context) { + ctx := c.Request.Context() id := c.Param("keyID") key, err := ocr2kc.App.GetKeyStore().OCR2().Get(id) if err != nil { jsonAPIError(c, http.StatusNotFound, err) return } - err = ocr2kc.App.GetKeyStore().OCR2().Delete(id) + err = ocr2kc.App.GetKeyStore().OCR2().Delete(ctx, id) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -81,6 +83,7 @@ func (ocr2kc *OCR2KeysController) Delete(c *gin.Context) { // "Post /keys/ocr/import" func (ocr2kc *OCR2KeysController) Import(c *gin.Context) { defer ocr2kc.App.GetLogger().ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -88,7 +91,7 @@ func (ocr2kc *OCR2KeysController) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - keyBundle, err := ocr2kc.App.GetKeyStore().OCR2().Import(bytes, oldPassword) + keyBundle, err := ocr2kc.App.GetKeyStore().OCR2().Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/ocr2_keys_controller_test.go b/core/web/ocr2_keys_controller_test.go index 815ae3ac20b..a8f480a1520 100644 --- a/core/web/ocr2_keys_controller_test.go +++ b/core/web/ocr2_keys_controller_test.go @@ -81,11 +81,12 @@ func TestOCR2KeysController_Delete_NonExistentOCRKeyID(t *testing.T) { } func TestOCR2KeysController_Delete_HappyPath(t *testing.T) { + ctx := testutils.Context(t) client, OCRKeyStore := setupOCR2KeysControllerTests(t) keys, _ := OCRKeyStore.GetAll() initialLength := len(keys) - key, _ := OCRKeyStore.Create("evm") + key, _ := OCRKeyStore.Create(ctx, "evm") response, cleanup := client.Delete("/v2/keys/ocr2/" + key.ID()) t.Cleanup(cleanup) @@ -98,12 +99,13 @@ func TestOCR2KeysController_Delete_HappyPath(t *testing.T) { func setupOCR2KeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.OCR2) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) client := app.NewHTTPClient(nil) - require.NoError(t, app.KeyStore.OCR2().Add(cltest.DefaultOCR2Key)) + require.NoError(t, app.KeyStore.OCR2().Add(ctx, cltest.DefaultOCR2Key)) return client, app.GetKeyStore().OCR2() } diff --git a/core/web/ocr_keys_controller.go b/core/web/ocr_keys_controller.go index 12eaa76372c..9be5dbf33d9 100644 --- a/core/web/ocr_keys_controller.go +++ b/core/web/ocr_keys_controller.go @@ -32,7 +32,8 @@ func (ocrkc *OCRKeysController) Index(c *gin.Context) { // Example: // "POST /keys/ocr" func (ocrkc *OCRKeysController) Create(c *gin.Context) { - key, err := ocrkc.App.GetKeyStore().OCR().Create() + ctx := c.Request.Context() + key, err := ocrkc.App.GetKeyStore().OCR().Create(ctx) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -50,13 +51,14 @@ func (ocrkc *OCRKeysController) Create(c *gin.Context) { // "DELETE /keys/ocr/:keyID" // "DELETE /keys/ocr/:keyID?hard=true" func (ocrkc *OCRKeysController) Delete(c *gin.Context) { + ctx := c.Request.Context() id := c.Param("keyID") key, err := ocrkc.App.GetKeyStore().OCR().Get(id) if err != nil { jsonAPIError(c, http.StatusNotFound, err) return } - _, err = ocrkc.App.GetKeyStore().OCR().Delete(id) + _, err = ocrkc.App.GetKeyStore().OCR().Delete(ctx, id) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -71,6 +73,7 @@ func (ocrkc *OCRKeysController) Delete(c *gin.Context) { // "Post /keys/ocr/import" func (ocrkc *OCRKeysController) Import(c *gin.Context) { defer ocrkc.App.GetLogger().ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -78,7 +81,7 @@ func (ocrkc *OCRKeysController) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - encryptedOCRKeyBundle, err := ocrkc.App.GetKeyStore().OCR().Import(bytes, oldPassword) + encryptedOCRKeyBundle, err := ocrkc.App.GetKeyStore().OCR().Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/ocr_keys_controller_test.go b/core/web/ocr_keys_controller_test.go index 31422f47c0c..82a0b9ebc2d 100644 --- a/core/web/ocr_keys_controller_test.go +++ b/core/web/ocr_keys_controller_test.go @@ -69,11 +69,12 @@ func TestOCRKeysController_Delete_NonExistentOCRKeyID(t *testing.T) { } func TestOCRKeysController_Delete_HappyPath(t *testing.T) { + ctx := testutils.Context(t) client, OCRKeyStore := setupOCRKeysControllerTests(t) keys, _ := OCRKeyStore.GetAll() initialLength := len(keys) - key, _ := OCRKeyStore.Create() + key, _ := OCRKeyStore.Create(ctx) response, cleanup := client.Delete("/v2/keys/ocr/" + key.ID()) t.Cleanup(cleanup) @@ -86,12 +87,13 @@ func TestOCRKeysController_Delete_HappyPath(t *testing.T) { func setupOCRKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.OCR) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) client := app.NewHTTPClient(nil) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) return client, app.GetKeyStore().OCR() } diff --git a/core/web/p2p_keys_controller.go b/core/web/p2p_keys_controller.go index bbe9d83f741..042f44b7bc5 100644 --- a/core/web/p2p_keys_controller.go +++ b/core/web/p2p_keys_controller.go @@ -35,7 +35,8 @@ const keyType = "Ed25519" // Example: // "POST /keys/p2p" func (p2pkc *P2PKeysController) Create(c *gin.Context) { - key, err := p2pkc.App.GetKeyStore().P2P().Create() + ctx := c.Request.Context() + key, err := p2pkc.App.GetKeyStore().P2P().Create(ctx) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -56,6 +57,7 @@ func (p2pkc *P2PKeysController) Create(c *gin.Context) { // "DELETE /keys/p2p/:keyID" // "DELETE /keys/p2p/:keyID?hard=true" func (p2pkc *P2PKeysController) Delete(c *gin.Context) { + ctx := c.Request.Context() keyID, err := p2pkey.MakePeerID(c.Param("keyID")) if err != nil { jsonAPIError(c, http.StatusUnprocessableEntity, err) @@ -66,7 +68,7 @@ func (p2pkc *P2PKeysController) Delete(c *gin.Context) { jsonAPIError(c, http.StatusNotFound, err) return } - _, err = p2pkc.App.GetKeyStore().P2P().Delete(key.PeerID()) + _, err = p2pkc.App.GetKeyStore().P2P().Delete(ctx, key.PeerID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -85,6 +87,7 @@ func (p2pkc *P2PKeysController) Delete(c *gin.Context) { // "Post /keys/p2p/import" func (p2pkc *P2PKeysController) Import(c *gin.Context) { defer p2pkc.App.GetLogger().ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -92,7 +95,7 @@ func (p2pkc *P2PKeysController) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - key, err := p2pkc.App.GetKeyStore().P2P().Import(bytes, oldPassword) + key, err := p2pkc.App.GetKeyStore().P2P().Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/p2p_keys_controller_test.go b/core/web/p2p_keys_controller_test.go index df6f556fcb8..63cea5f0ea7 100644 --- a/core/web/p2p_keys_controller_test.go +++ b/core/web/p2p_keys_controller_test.go @@ -91,12 +91,13 @@ func TestP2PKeysController_Delete_InvalidPeerID(t *testing.T) { func TestP2PKeysController_Delete_HappyPath(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client, keyStore := setupP2PKeysControllerTests(t) keys, _ := keyStore.P2P().GetAll() initialLength := len(keys) - key, _ := keyStore.P2P().Create() + key, _ := keyStore.P2P().Create(ctx) response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/p2p/%s", key.ID())) t.Cleanup(cleanup) @@ -109,11 +110,12 @@ func TestP2PKeysController_Delete_HappyPath(t *testing.T) { func setupP2PKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { t.Helper() + ctx := testutils.Context(t) app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.KeyStore.P2P().Add(cltest.DefaultP2PKey)) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.P2P().Add(ctx, cltest.DefaultP2PKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/pipeline_runs_controller.go b/core/web/pipeline_runs_controller.go index 2c6caa648fc..1bd52b021c3 100644 --- a/core/web/pipeline_runs_controller.go +++ b/core/web/pipeline_runs_controller.go @@ -66,6 +66,7 @@ func (prc *PipelineRunsController) Index(c *gin.Context, size, page, offset int) // Example: // "GET /jobs/:ID/runs/:runID" func (prc *PipelineRunsController) Show(c *gin.Context) { + ctx := c.Request.Context() pipelineRun := pipeline.Run{} err := pipelineRun.SetID(c.Param("runID")) if err != nil { @@ -73,7 +74,7 @@ func (prc *PipelineRunsController) Show(c *gin.Context) { return } - pipelineRun, err = prc.App.PipelineORM().FindRun(pipelineRun.ID) + pipelineRun, err = prc.App.PipelineORM().FindRun(ctx, pipelineRun.ID) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -87,8 +88,9 @@ func (prc *PipelineRunsController) Show(c *gin.Context) { // Example: // "POST /jobs/:ID/runs" func (prc *PipelineRunsController) Create(c *gin.Context) { + ctx := c.Request.Context() respondWithPipelineRun := func(jobRunID int64) { - pipelineRun, err := prc.App.PipelineORM().FindRun(jobRunID) + pipelineRun, err := prc.App.PipelineORM().FindRun(ctx, jobRunID) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index a270a0a92b8..f6b4291a34f 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -250,6 +250,7 @@ func TestPipelineRunsController_ShowRun_InvalidID(t *testing.T) { func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, int32, []int64) { t.Parallel() + ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -261,8 +262,8 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, ethClient, cltest.DefaultP2PKey) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) client := app.NewHTTPClient(nil) key, _ := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 296add4ee25..12b958a346d 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -15,7 +15,6 @@ import ( clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -167,7 +166,7 @@ func NewOffChainReportingSpec(spec *job.OCROracleSpec) *OffChainReportingSpec { // OffChainReporting2Spec defines the spec details of a OffChainReporting2 Job type OffChainReporting2Spec struct { ContractID string `json:"contractID"` - Relay relay.Network `json:"relay"` + Relay string `json:"relay"` // RelayID.Network RelayConfig map[string]interface{} `json:"relayConfig"` P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` OCRKeyBundleID null.String `json:"ocrKeyBundleID"` @@ -392,7 +391,7 @@ func NewBlockHeaderFeederSpec(spec *job.BlockHeaderFeederSpec) *BlockHeaderFeede // BootstrapSpec defines the spec details of a BootstrapSpec Job type BootstrapSpec struct { ContractID string `json:"contractID"` - Relay relay.Network `json:"relay"` + Relay string `json:"relay"` // RelayID.Network RelayConfig map[string]interface{} `json:"relayConfig"` BlockchainTimeout models.Interval `json:"blockchainTimeout"` ContractConfigTrackerSubscribeInterval models.Interval `json:"contractConfigTrackerSubscribeInterval"` diff --git a/core/web/resolver/csa_keys_test.go b/core/web/resolver/csa_keys_test.go index a94a934efa3..1048d9aa4bc 100644 --- a/core/web/resolver/csa_keys_test.go +++ b/core/web/resolver/csa_keys_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -109,7 +110,7 @@ func Test_CreateCSAKey(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.csa.On("Create").Return(fakeKey, nil) + f.Mocks.csa.On("Create", mock.Anything).Return(fakeKey, nil) f.Mocks.keystore.On("CSA").Return(f.Mocks.csa) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -120,7 +121,7 @@ func Test_CreateCSAKey(t *testing.T) { name: "csa key exists error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.csa.On("Create").Return(csakey.KeyV2{}, keystore.ErrCSAKeyExists) + f.Mocks.csa.On("Create", mock.Anything).Return(csakey.KeyV2{}, keystore.ErrCSAKeyExists) f.Mocks.keystore.On("CSA").Return(f.Mocks.csa) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -180,7 +181,7 @@ func Test_DeleteCSAKey(t *testing.T) { before: func(f *gqlTestFramework) { f.App.On("GetKeyStore").Return(f.Mocks.keystore) f.Mocks.keystore.On("CSA").Return(f.Mocks.csa) - f.Mocks.csa.On("Delete", fakeKey.ID()).Return(fakeKey, nil) + f.Mocks.csa.On("Delete", mock.Anything, fakeKey.ID()).Return(fakeKey, nil) }, query: query, variables: variables, @@ -193,7 +194,7 @@ func Test_DeleteCSAKey(t *testing.T) { f.App.On("GetKeyStore").Return(f.Mocks.keystore) f.Mocks.keystore.On("CSA").Return(f.Mocks.csa) f.Mocks.csa. - On("Delete", fakeKey.ID()). + On("Delete", mock.Anything, fakeKey.ID()). Return(csakey.KeyV2{}, keystore.KeyNotFoundError{ID: fakeKey.ID(), KeyType: "CSA"}) }, query: query, diff --git a/core/web/resolver/job_run_test.go b/core/web/resolver/job_run_test.go index 18036311155..a35a2f66ac5 100644 --- a/core/web/resolver/job_run_test.go +++ b/core/web/resolver/job_run_test.go @@ -286,7 +286,7 @@ func TestResolver_RunJob(t *testing.T) { authenticated: true, before: func(f *gqlTestFramework) { f.App.On("RunJobV2", mock.Anything, id, (map[string]interface{})(nil)).Return(int64(25), nil) - f.Mocks.pipelineORM.On("FindRun", int64(25)).Return(pipeline.Run{ + f.Mocks.pipelineORM.On("FindRun", mock.Anything, int64(25)).Return(pipeline.Run{ ID: 2, PipelineSpecID: 5, CreatedAt: f.Timestamp(), @@ -377,7 +377,7 @@ func TestResolver_RunJob(t *testing.T) { authenticated: true, before: func(f *gqlTestFramework) { f.App.On("RunJobV2", mock.Anything, id, (map[string]interface{})(nil)).Return(int64(25), nil) - f.Mocks.pipelineORM.On("FindRun", int64(25)).Return(pipeline.Run{}, gError) + f.Mocks.pipelineORM.On("FindRun", mock.Anything, int64(25)).Return(pipeline.Run{}, gError) f.App.On("PipelineORM").Return(f.Mocks.pipelineORM) }, query: mutation, diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 85f3407169e..9663f9dfe82 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -113,7 +113,7 @@ func (r *Resolver) CreateCSAKey(ctx context.Context) (*CreateCSAKeyPayloadResolv return nil, err } - key, err := r.App.GetKeyStore().CSA().Create() + key, err := r.App.GetKeyStore().CSA().Create(ctx) if err != nil { if errors.Is(err, keystore.ErrCSAKeyExists) { return NewCreateCSAKeyPayload(nil, err), nil @@ -137,7 +137,7 @@ func (r *Resolver) DeleteCSAKey(ctx context.Context, args struct { return nil, err } - key, err := r.App.GetKeyStore().CSA().Delete(string(args.ID)) + key, err := r.App.GetKeyStore().CSA().Delete(ctx, string(args.ID)) if err != nil { if errors.As(err, &keystore.KeyNotFoundError{}) { return NewDeleteCSAKeyPayload(csakey.KeyV2{}, err), nil @@ -561,7 +561,7 @@ func (r *Resolver) CreateOCRKeyBundle(ctx context.Context) (*CreateOCRKeyBundleP return nil, err } - key, err := r.App.GetKeyStore().OCR().Create() + key, err := r.App.GetKeyStore().OCR().Create(ctx) if err != nil { return nil, err } @@ -581,7 +581,7 @@ func (r *Resolver) DeleteOCRKeyBundle(ctx context.Context, args struct { return nil, err } - deletedKey, err := r.App.GetKeyStore().OCR().Delete(args.ID) + deletedKey, err := r.App.GetKeyStore().OCR().Delete(ctx, args.ID) if err != nil { if errors.As(err, &keystore.KeyNotFoundError{}) { return NewDeleteOCRKeyBundlePayloadResolver(ocrkey.KeyV2{}, err), nil @@ -636,7 +636,7 @@ func (r *Resolver) CreateP2PKey(ctx context.Context) (*CreateP2PKeyPayloadResolv return nil, err } - key, err := r.App.GetKeyStore().P2P().Create() + key, err := r.App.GetKeyStore().P2P().Create(ctx) if err != nil { return nil, err } @@ -665,7 +665,7 @@ func (r *Resolver) DeleteP2PKey(ctx context.Context, args struct { return nil, err } - key, err := r.App.GetKeyStore().P2P().Delete(keyID) + key, err := r.App.GetKeyStore().P2P().Delete(ctx, keyID) if err != nil { if errors.As(err, &keystore.KeyNotFoundError{}) { return NewDeleteP2PKeyPayload(p2pkey.KeyV2{}, err), nil @@ -686,7 +686,7 @@ func (r *Resolver) CreateVRFKey(ctx context.Context) (*CreateVRFKeyPayloadResolv return nil, err } - key, err := r.App.GetKeyStore().VRF().Create() + key, err := r.App.GetKeyStore().VRF().Create(ctx) if err != nil { return nil, err } @@ -708,7 +708,7 @@ func (r *Resolver) DeleteVRFKey(ctx context.Context, args struct { return nil, err } - key, err := r.App.GetKeyStore().VRF().Delete(string(args.ID)) + key, err := r.App.GetKeyStore().VRF().Delete(ctx, string(args.ID)) if err != nil { if errors.Is(errors.Cause(err), keystore.ErrMissingVRFKey) { return NewDeleteVRFKeyPayloadResolver(vrfkey.KeyV2{}, err), nil @@ -1019,7 +1019,7 @@ func (r *Resolver) CreateJob(ctx context.Context, args struct { config := r.App.GetConfig() switch jbt { case job.OffchainReporting: - jb, err = ocr.ValidatedOracleSpecToml(r.App.GetRelayers().LegacyEVMChains(), args.Input.TOML) + jb, err = ocr.ValidatedOracleSpecToml(config, r.App.GetRelayers().LegacyEVMChains(), args.Input.TOML) if !config.OCR().Enabled() { return nil, errors.New("The Offchain Reporting feature is disabled by configuration") } @@ -1162,7 +1162,7 @@ func (r *Resolver) RunJob(ctx context.Context, args struct { return nil, err } - plnRun, err := r.App.PipelineORM().FindRun(jobRunID) + plnRun, err := r.App.PipelineORM().FindRun(ctx, jobRunID) if err != nil { return nil, err } @@ -1206,7 +1206,7 @@ func (r *Resolver) CreateOCR2KeyBundle(ctx context.Context, args struct { ct := FromOCR2ChainType(args.ChainType) - key, err := r.App.GetKeyStore().OCR2().Create(chaintype.ChainType(ct)) + key, err := r.App.GetKeyStore().OCR2().Create(ctx, chaintype.ChainType(ct)) if err != nil { // Not covering the `chaintype.ErrInvalidChainType` since the GQL model would prevent a non-accepted chain-type from being received return nil, err @@ -1238,7 +1238,7 @@ func (r *Resolver) DeleteOCR2KeyBundle(ctx context.Context, args struct { return NewDeleteOCR2KeyBundlePayloadResolver(nil, err), nil } - err = r.App.GetKeyStore().OCR2().Delete(id) + err = r.App.GetKeyStore().OCR2().Delete(ctx, id) if err != nil { return nil, err } diff --git a/core/web/resolver/ocr2_keys_test.go b/core/web/resolver/ocr2_keys_test.go index 35ee1925cdb..fc82d070dd9 100644 --- a/core/web/resolver/ocr2_keys_test.go +++ b/core/web/resolver/ocr2_keys_test.go @@ -8,13 +8,13 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestResolver_GetOCR2KeyBundles(t *testing.T) { @@ -151,7 +151,7 @@ func TestResolver_CreateOCR2KeyBundle(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr2.On("Create", chaintype.ChainType("evm")).Return(fakeKey, nil) + f.Mocks.ocr2.On("Create", mock.Anything, chaintype.ChainType("evm")).Return(fakeKey, nil) f.Mocks.keystore.On("OCR2").Return(f.Mocks.ocr2) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -163,7 +163,7 @@ func TestResolver_CreateOCR2KeyBundle(t *testing.T) { name: "generic error on Create()", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr2.On("Create", chaintype.ChainType("evm")).Return(nil, gError) + f.Mocks.ocr2.On("Create", mock.Anything, chaintype.ChainType("evm")).Return(nil, gError) f.Mocks.keystore.On("OCR2").Return(f.Mocks.ocr2) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -239,7 +239,7 @@ func TestResolver_DeleteOCR2KeyBundle(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr2.On("Delete", fakeKey.ID()).Return(nil) + f.Mocks.ocr2.On("Delete", mock.Anything, fakeKey.ID()).Return(nil) f.Mocks.ocr2.On("Get", fakeKey.ID()).Return(fakeKey, nil) f.Mocks.keystore.On("OCR2").Return(f.Mocks.ocr2) f.App.On("GetKeyStore").Return(f.Mocks.keystore) @@ -269,7 +269,7 @@ func TestResolver_DeleteOCR2KeyBundle(t *testing.T) { name: "generic error on Delete()", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr2.On("Delete", fakeKey.ID()).Return(gError) + f.Mocks.ocr2.On("Delete", mock.Anything, fakeKey.ID()).Return(gError) f.Mocks.ocr2.On("Get", fakeKey.ID()).Return(fakeKey, nil) f.Mocks.keystore.On("OCR2").Return(f.Mocks.ocr2) f.App.On("GetKeyStore").Return(f.Mocks.keystore) diff --git a/core/web/resolver/ocr_test.go b/core/web/resolver/ocr_test.go index d1a0351842d..5ca56c4bd04 100644 --- a/core/web/resolver/ocr_test.go +++ b/core/web/resolver/ocr_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -105,7 +106,7 @@ func TestResolver_OCRCreateBundle(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr.On("Create").Return(fakeKey, nil) + f.Mocks.ocr.On("Create", mock.Anything).Return(fakeKey, nil) f.Mocks.keystore.On("OCR").Return(f.Mocks.ocr) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -163,7 +164,7 @@ func TestResolver_OCRDeleteBundle(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ocr.On("Delete", fakeKey.ID()).Return(fakeKey, nil) + f.Mocks.ocr.On("Delete", mock.Anything, fakeKey.ID()).Return(fakeKey, nil) f.Mocks.keystore.On("OCR").Return(f.Mocks.ocr) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -176,7 +177,7 @@ func TestResolver_OCRDeleteBundle(t *testing.T) { authenticated: true, before: func(f *gqlTestFramework) { f.Mocks.ocr. - On("Delete", fakeKey.ID()). + On("Delete", mock.Anything, fakeKey.ID()). Return(ocrkey.KeyV2{}, keystore.KeyNotFoundError{ID: "helloWorld", KeyType: "OCR"}) f.Mocks.keystore.On("OCR").Return(f.Mocks.ocr) f.App.On("GetKeyStore").Return(f.Mocks.keystore) diff --git a/core/web/resolver/p2p_test.go b/core/web/resolver/p2p_test.go index e2470f7fac5..6502ffc821a 100644 --- a/core/web/resolver/p2p_test.go +++ b/core/web/resolver/p2p_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -102,7 +103,7 @@ func TestResolver_CreateP2PKey(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.p2p.On("Create").Return(fakeKey, nil) + f.Mocks.p2p.On("Create", mock.Anything).Return(fakeKey, nil) f.Mocks.keystore.On("P2P").Return(f.Mocks.p2p) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -163,7 +164,7 @@ func TestResolver_DeleteP2PKey(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.p2p.On("Delete", peerID).Return(fakeKey, nil) + f.Mocks.p2p.On("Delete", mock.Anything, peerID).Return(fakeKey, nil) f.Mocks.keystore.On("P2P").Return(f.Mocks.p2p) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -176,7 +177,7 @@ func TestResolver_DeleteP2PKey(t *testing.T) { authenticated: true, before: func(f *gqlTestFramework) { f.Mocks.p2p. - On("Delete", peerID). + On("Delete", mock.Anything, peerID). Return( p2pkey.KeyV2{}, keystore.KeyNotFoundError{ID: peerID.String(), KeyType: "P2P"}, diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index 5a016599dc9..e24974e765d 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" ) @@ -69,7 +68,7 @@ func (r *Resolver) Chain(ctx context.Context, args struct{ ID graphql.ID }) (*Ch return nil, err } - cs, _, err := r.App.EVMORM().Chains(relay.ChainID(args.ID)) + cs, _, err := r.App.EVMORM().Chains(string(args.ID)) if err != nil { return nil, err } diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 1b65549488f..7021576fdcf 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -17,7 +17,6 @@ import ( ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -485,7 +484,7 @@ func TestResolver_OCR2Spec(t *testing.T) { OCRKeyBundleID: null.StringFrom(keyBundleID.String()), MonitoringEndpoint: null.StringFrom("https://monitor.endpoint"), P2PV2Bootstrappers: pq.StringArray{"12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"}, - Relay: relay.EVM, + Relay: types.NetworkEVM, RelayConfig: relayConfig, TransmitterID: null.StringFrom(transmitterAddress.String()), PluginType: types.Median, diff --git a/core/web/resolver/vrf_test.go b/core/web/resolver/vrf_test.go index e1ee73b9984..5101bc5937b 100644 --- a/core/web/resolver/vrf_test.go +++ b/core/web/resolver/vrf_test.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" @@ -198,7 +199,7 @@ func TestResolver_CreateVRFKey(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.vrf.On("Create").Return(fakeKey, nil) + f.Mocks.vrf.On("Create", mock.Anything).Return(fakeKey, nil) f.Mocks.keystore.On("VRF").Return(f.Mocks.vrf) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -261,7 +262,7 @@ func TestResolver_DeleteVRFKey(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.vrf.On("Delete", fakeKey.PublicKey.String()).Return(fakeKey, nil) + f.Mocks.vrf.On("Delete", mock.Anything, fakeKey.PublicKey.String()).Return(fakeKey, nil) f.Mocks.keystore.On("VRF").Return(f.Mocks.vrf) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -274,7 +275,7 @@ func TestResolver_DeleteVRFKey(t *testing.T) { authenticated: true, before: func(f *gqlTestFramework) { f.Mocks.vrf. - On("Delete", fakeKey.PublicKey.String()). + On("Delete", mock.Anything, fakeKey.PublicKey.String()). Return(vrfkey.KeyV2{}, errors.Wrapf( keystore.ErrMissingVRFKey, "unable to find VRF key with id %s", diff --git a/core/web/solana_chains_controller.go b/core/web/solana_chains_controller.go index 8e2d4393a5f..ffb39cddba1 100644 --- a/core/web/solana_chains_controller.go +++ b/core/web/solana_chains_controller.go @@ -1,15 +1,15 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) func NewSolanaChainsController(app chainlink.Application) ChainsController { return newChainsController( - relay.Solana, - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.Solana)), + types.NetworkSolana, + app.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkSolana)), ErrSolanaNotEnabled, presenters.NewSolanaChainResource, app.GetLogger(), diff --git a/core/web/solana_keys_controller_test.go b/core/web/solana_keys_controller_test.go index 94b11207c92..b71f8287d0f 100644 --- a/core/web/solana_keys_controller_test.go +++ b/core/web/solana_keys_controller_test.go @@ -5,15 +5,15 @@ import ( "net/http" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestSolanaKeysController_Index_HappyPath(t *testing.T) { @@ -75,12 +75,13 @@ func TestSolanaKeysController_Delete_NonExistentSolanaKeyID(t *testing.T) { func TestSolanaKeysController_Delete_HappyPath(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client, keyStore := setupSolanaKeysControllerTests(t) keys, _ := keyStore.Solana().GetAll() initialLength := len(keys) - key, _ := keyStore.Solana().Create() + key, _ := keyStore.Solana().Create(ctx) response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/solana/%s", key.ID())) t.Cleanup(cleanup) @@ -93,11 +94,12 @@ func TestSolanaKeysController_Delete_HappyPath(t *testing.T) { func setupSolanaKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { t.Helper() + ctx := testutils.Context(t) app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.KeyStore.Solana().Add(cltest.DefaultSolanaKey)) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.Solana().Add(ctx, cltest.DefaultSolanaKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/solana_nodes_controller.go b/core/web/solana_nodes_controller.go index d5fbc05ccf5..b3e03b8c320 100644 --- a/core/web/solana_nodes_controller.go +++ b/core/web/solana_nodes_controller.go @@ -1,8 +1,8 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -10,7 +10,7 @@ import ( var ErrSolanaNotEnabled = errChainDisabled{name: "Solana", tomlKey: "Solana.Enabled"} func NewSolanaNodesController(app chainlink.Application) NodesController { - scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.Solana) + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), types.NetworkSolana) return newNodesController[presenters.SolanaNodeResource]( scopedNodeStatuser, ErrSolanaNotEnabled, presenters.NewSolanaNodeResource, app.GetAuditLogger()) diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index 70218080a87..7885c73bf7a 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -8,10 +8,10 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" solanamodels "github.com/smartcontractkit/chainlink/v2/core/store/models/solana" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -23,7 +23,7 @@ type SolanaTransfersController struct { // Create sends SOL and other native coins from the Chainlink's account to a specified address. func (tc *SolanaTransfersController) Create(c *gin.Context) { - relayers := tc.App.GetRelayers().List(chainlink.FilterRelayersByType(relay.Solana)) + relayers := tc.App.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkSolana)) if relayers == nil { jsonAPIError(c, http.StatusBadRequest, ErrSolanaNotEnabled) return @@ -48,7 +48,7 @@ func (tc *SolanaTransfersController) Create(c *gin.Context) { } amount := new(big.Int).SetUint64(tr.Amount) - relayerID := relay.ID{Network: relay.Solana, ChainID: tr.SolanaChainID} + relayerID := types.RelayID{Network: types.NetworkSolana, ChainID: tr.SolanaChainID} relayer, err := relayers.Get(relayerID) if err != nil { if errors.Is(err, chainlink.ErrNoSuchRelayer) { diff --git a/core/web/starknet_chains_controller.go b/core/web/starknet_chains_controller.go index 414e17d9823..35a06899117 100644 --- a/core/web/starknet_chains_controller.go +++ b/core/web/starknet_chains_controller.go @@ -1,15 +1,15 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) func NewStarkNetChainsController(app chainlink.Application) ChainsController { return newChainsController( - relay.StarkNet, - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.StarkNet)), + types.NetworkStarkNet, + app.GetRelayers().List(chainlink.FilterRelayersByType(types.NetworkStarkNet)), ErrStarkNetNotEnabled, presenters.NewStarkNetChainResource, app.GetLogger(), diff --git a/core/web/starknet_keys_controller_test.go b/core/web/starknet_keys_controller_test.go index 9215fb8f9c5..05f611f2f22 100644 --- a/core/web/starknet_keys_controller_test.go +++ b/core/web/starknet_keys_controller_test.go @@ -75,12 +75,13 @@ func TestStarkNetKeysController_Delete_NonExistentStarkNetKeyID(t *testing.T) { func TestStarkNetKeysController_Delete_HappyPath(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client, keyStore := setupStarkNetKeysControllerTests(t) keys, _ := keyStore.StarkNet().GetAll() initialLength := len(keys) - key, _ := keyStore.StarkNet().Create() + key, _ := keyStore.StarkNet().Create(ctx) response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/starknet/%s", key.ID())) t.Cleanup(cleanup) @@ -93,11 +94,12 @@ func TestStarkNetKeysController_Delete_HappyPath(t *testing.T) { func setupStarkNetKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { t.Helper() + ctx := testutils.Context(t) app := cltest.NewApplication(t) - require.NoError(t, app.Start(testutils.Context(t))) - require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.KeyStore.StarkNet().Add(cltest.DefaultStarkNetKey)) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + require.NoError(t, app.KeyStore.StarkNet().Add(ctx, cltest.DefaultStarkNetKey)) client := app.NewHTTPClient(nil) diff --git a/core/web/starknet_nodes_controller.go b/core/web/starknet_nodes_controller.go index d2881f2e65a..5d059d357f0 100644 --- a/core/web/starknet_nodes_controller.go +++ b/core/web/starknet_nodes_controller.go @@ -1,8 +1,8 @@ package web import ( + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -10,7 +10,7 @@ import ( var ErrStarkNetNotEnabled = errChainDisabled{name: "StarkNet", tomlKey: "Starknet.Enabled"} func NewStarkNetNodesController(app chainlink.Application) NodesController { - scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.StarkNet) + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), types.NetworkStarkNet) return newNodesController[presenters.StarkNetNodeResource]( scopedNodeStatuser, ErrStarkNetNotEnabled, presenters.NewStarkNetNodeResource, app.GetAuditLogger()) diff --git a/core/web/vrf_keys_controller.go b/core/web/vrf_keys_controller.go index a54a3f9d596..567b8acc995 100644 --- a/core/web/vrf_keys_controller.go +++ b/core/web/vrf_keys_controller.go @@ -32,7 +32,8 @@ func (vrfkc *VRFKeysController) Index(c *gin.Context) { // Example: // "POST /keys/vrf" func (vrfkc *VRFKeysController) Create(c *gin.Context) { - pk, err := vrfkc.App.GetKeyStore().VRF().Create() + ctx := c.Request.Context() + pk, err := vrfkc.App.GetKeyStore().VRF().Create(ctx) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -53,13 +54,14 @@ func (vrfkc *VRFKeysController) Create(c *gin.Context) { // "DELETE /keys/vrf/:keyID" // "DELETE /keys/vrf/:keyID?hard=true" func (vrfkc *VRFKeysController) Delete(c *gin.Context) { + ctx := c.Request.Context() keyID := c.Param("keyID") key, err := vrfkc.App.GetKeyStore().VRF().Get(keyID) if err != nil { jsonAPIError(c, http.StatusNotFound, err) return } - _, err = vrfkc.App.GetKeyStore().VRF().Delete(keyID) + _, err = vrfkc.App.GetKeyStore().VRF().Delete(ctx, keyID) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -78,6 +80,7 @@ func (vrfkc *VRFKeysController) Delete(c *gin.Context) { // "Post /keys/vrf/import" func (vrfkc *VRFKeysController) Import(c *gin.Context) { defer vrfkc.App.GetLogger().ErrorIfFn(c.Request.Body.Close, "Error closing Import request body") + ctx := c.Request.Context() bytes, err := io.ReadAll(c.Request.Body) if err != nil { @@ -85,7 +88,7 @@ func (vrfkc *VRFKeysController) Import(c *gin.Context) { return } oldPassword := c.Query("oldpassword") - key, err := vrfkc.App.GetKeyStore().VRF().Import(bytes, oldPassword) + key, err := vrfkc.App.GetKeyStore().VRF().Import(ctx, bytes, oldPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/charts/chainlink-cluster/.env.example b/crib/.env.example similarity index 100% rename from charts/chainlink-cluster/.env.example rename to crib/.env.example diff --git a/crib/README.md b/crib/README.md new file mode 100644 index 00000000000..c9106d401cd --- /dev/null +++ b/crib/README.md @@ -0,0 +1,156 @@ +# Crib Devspace Setup + +CRIB is a devspace configuration to launch chainlink cluster for system level tests + +Install `kubefwd` (no nixpkg for it yet, planned) + +``` +brew install txn2/tap/kubefwd +``` + +If you want to build images you need [docker](https://docs.docker.com/engine/install/) service running + +Enter the shell (from the root project dir) + +``` +nix develop +``` + +# Develop + +## New cluster + +We are using [devspace](https://www.devspace.sh/docs/getting-started/installation?x0=3) + +Configure the cluster, see `deployments.app.helm.values` and [values.yaml](../charts/chainlink-cluster/values.yaml) comments for more details + +Set up your K8s access + +``` +export DEVSPACE_IMAGE="..." +./setup.sh ${my-personal-namespace-name-crib} +``` + +Create a .env file based on the .env.sample file + +```sh +cp .env.sample .env +# Fill in the required values in .env +``` + +Build and deploy the current state of your repository + +``` +devspace deploy +``` + +Default `ttl` is `72h`, use `ttl` command to update if you need more time + +Valid values are `1h`, `2m`, `3s`, etc. Go time format is invalid `1h2m3s` + +``` +devspace run ttl ${namespace} 120h +``` + +If you want to deploy an image tag that is already available in ECR, use: + +``` +devspace deploy --override-image-tag "" +``` + +If you want to deploy an image tag from a public ECR repo, use: + +``` +export DEVSPACE_IMAGE=public.ecr.aws/chainlink/chainlink +devspace deploy --override-image-tag 2.9.0 +``` + +Forward ports to check UI or run tests + +``` +devspace run connect ${my-personal-namespace-name-crib} +``` + +List ingress hostnames + +``` +devspace run ingress-hosts +``` + +Destroy the cluster + +``` +devspace purge +``` + +## Running load tests + +Check this [doc](../../integration-tests/load/ocr/README.md) + +If you used `devspace dev ...` always use `devspace reset pods` to switch the pods back + +# Helm + +If you would like to use `helm` directly, please uncomment data in `values.yaml` + +## Install from local files + +``` +helm install -f values.yaml cl-cluster . +``` + +Forward all apps (in another terminal) + +``` +sudo kubefwd svc -n cl-cluster +``` + +Then you can connect and run your tests + +# Grafana dashboard + +We are using [Grabana](https://github.com/K-Phoen/grabana) lib to create dashboards programmatically + +You can also select dashboard platform in `INFRA_PLATFORM` either `kubernetes` or `docker` + +You can select the dashboard panels with `PANELS_INCLUDED` which is a list of panel names separated by comma +If you don't specify it will include core panels by default + +``` +export LOKI_TENANT_ID=promtail +export LOKI_URL=... +export GRAFANA_URL=... +export GRAFANA_TOKEN=... +export PROMETHEUS_DATA_SOURCE_NAME=Thanos +export LOKI_DATA_SOURCE_NAME=Loki +export INFRA_PLATFORM=kubernetes +export GRAFANA_FOLDER=DashboardCoreDebug +export DASHBOARD_NAME=CL-Cluster + +devspace run dashboard_deploy +``` + +Open Grafana folder `DashboardCoreDebug` and find dashboard `ChainlinkClusterDebug` + +# Testing + +Deploy your dashboard and run soak/load [tests](../../integration-tests/load/), check [README](../../integration-tests/README.md) for further explanations + +``` +devspace run dashboard_deploy +devspace run workload +devspace run dashboard_test +``` + +# Local Testing + +Go to [dashboard-lib](../dashboard-lib) and link the modules locally + +``` +cd dashboard +pnpm link --global +cd crib/dashboard/tests +pnpm link --global dashboard-tests +``` + +Then run the tests with commands mentioned above diff --git a/charts/chainlink-cluster/dashboard/cmd/delete.go b/crib/dashboard/cmd/delete.go similarity index 100% rename from charts/chainlink-cluster/dashboard/cmd/delete.go rename to crib/dashboard/cmd/delete.go diff --git a/charts/chainlink-cluster/dashboard/cmd/deploy.go b/crib/dashboard/cmd/deploy.go similarity index 84% rename from charts/chainlink-cluster/dashboard/cmd/deploy.go rename to crib/dashboard/cmd/deploy.go index 24c3af4589b..6ee19b909a4 100644 --- a/charts/chainlink-cluster/dashboard/cmd/deploy.go +++ b/crib/dashboard/cmd/deploy.go @@ -5,6 +5,7 @@ import ( lib "github.com/smartcontractkit/chainlink/dashboard-lib" atlas_don "github.com/smartcontractkit/chainlink/dashboard-lib/atlas-don" core_don "github.com/smartcontractkit/chainlink/dashboard-lib/core-don" + core_node_components "github.com/smartcontractkit/chainlink/dashboard-lib/core-node-components" k8spods "github.com/smartcontractkit/chainlink/dashboard-lib/k8s-pods" waspdb "github.com/smartcontractkit/wasp/dashboard" "strings" @@ -30,6 +31,16 @@ func main() { // TODO: refactor as a component later addWASPRows(db, cfg) } + if cfg.PanelsIncluded["core_components"] { + db.Add( + core_node_components.New( + core_node_components.Props{ + PrometheusDataSource: cfg.DataSources.Prometheus, + PlatformOpts: core_node_components.PlatformPanelOpts(), + }, + ), + ) + } if cfg.PanelsIncluded["ocr"] || cfg.PanelsIncluded["ocr2"] || cfg.PanelsIncluded["ocr3"] { for key := range cfg.PanelsIncluded { if strings.Contains(key, "ocr") { @@ -45,7 +56,7 @@ func main() { } } } - if cfg.Platform == "kubernetes" { + if !cfg.PanelsIncluded["core_components"] && cfg.Platform == "kubernetes" { db.Add( k8spods.New( k8spods.Props{ diff --git a/charts/chainlink-cluster/devspace.yaml b/crib/devspace.yaml similarity index 99% rename from charts/chainlink-cluster/devspace.yaml rename to crib/devspace.yaml index d46e28572bb..ca12e1ed205 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/crib/devspace.yaml @@ -52,7 +52,7 @@ commands: ttl: |- kubectl label namespace $1 cleanup.kyverno.io/ttl=$2 --overwrite workload: |- - cd ../../integration-tests/load/ocr && go test -v -run TestOCRLoad || cd - + cd ../integration-tests/load/ocr && go test -v -run TestOCRLoad || cd - dashboard_deploy: |- go run dashboard/cmd/deploy.go dashboard_test: |- @@ -98,7 +98,7 @@ deployments: releaseName: "app" chart: name: cl-cluster - path: . + path: ../charts/chainlink-cluster # for simplicity, we define all the values here # they can be defined the same way in values.yml # devspace merges these "values" with the "values.yaml" before deploy diff --git a/charts/chainlink-cluster/devspace_start.sh b/crib/devspace_start.sh similarity index 100% rename from charts/chainlink-cluster/devspace_start.sh rename to crib/devspace_start.sh diff --git a/charts/chainlink-cluster/go.mod b/crib/go.mod similarity index 95% rename from charts/chainlink-cluster/go.mod rename to crib/go.mod index 4a8dd43fd5f..28bcaece757 100644 --- a/charts/chainlink-cluster/go.mod +++ b/crib/go.mod @@ -34,5 +34,5 @@ replace ( github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 - github.com/smartcontractkit/chainlink/dashboard-lib => ../../dashboard-lib + github.com/smartcontractkit/chainlink/dashboard-lib => ./../dashboard-lib ) diff --git a/charts/chainlink-cluster/go.sum b/crib/go.sum similarity index 100% rename from charts/chainlink-cluster/go.sum rename to crib/go.sum diff --git a/charts/chainlink-cluster/scripts/ingress_check.sh b/crib/scripts/ingress_check.sh similarity index 100% rename from charts/chainlink-cluster/scripts/ingress_check.sh rename to crib/scripts/ingress_check.sh diff --git a/charts/chainlink-cluster/setup.sh b/crib/setup.sh similarity index 100% rename from charts/chainlink-cluster/setup.sh rename to crib/setup.sh diff --git a/dashboard-lib/README.md b/dashboard-lib/README.md index 44fd655c72a..ee8fa66a7c7 100644 --- a/dashboard-lib/README.md +++ b/dashboard-lib/README.md @@ -16,7 +16,7 @@ dashboard Each component should contain rows, logic and unique variables in `component.go` -Components should be imported from this module, see [example](../charts/chainlink-cluster/dashboard/cmd/deploy.go) +Components should be imported from this module, see [example](../crib/dashboard/cmd/deploy.go) ## How to convert from JSON using Grabana codegen utility 1. Download Grabana binary [here](https://github.com/K-Phoen/grabana/releases) diff --git a/dashboard-lib/core-node-components/component.go b/dashboard-lib/core-node-components/component.go new file mode 100644 index 00000000000..47e23c073ba --- /dev/null +++ b/dashboard-lib/core-node-components/component.go @@ -0,0 +1,175 @@ +package core_node_components + +import ( + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/stat" + "github.com/K-Phoen/grabana/table" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" + "github.com/K-Phoen/grabana/timeseries/axis" + "github.com/K-Phoen/grabana/variable/interval" + "github.com/K-Phoen/grabana/variable/query" +) + +type Props struct { + PrometheusDataSource string + PlatformOpts PlatformOpts +} + +func vars(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.VariableAsInterval( + "interval", + interval.Values([]string{"30s", "1m", "5m", "15m", "30m", "1h", "6h", "12h"}), + interval.Default("15m"), + ), + dashboard.VariableAsQuery( + "env", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request("label_values(up, env)"), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "cluster", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env"}, cluster)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "blockchain", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env", cluster="$cluster"}, blockchain)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "product", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain"}, product)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "network_type", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", product="$product"}, network_type)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "component", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", network_type="$network_type"}, component)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "service", + query.DataSource(p.PrometheusDataSource), + query.IncludeAll(), + query.Request(`label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", network_type="$network_type", component="$component"}, service)`), + query.Sort(query.NumericalAsc), + ), + dashboard.VariableAsQuery( + "service_id", + query.DataSource(p.PrometheusDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request(`label_values(health{env="$env", cluster="$cluster", blockchain="$blockchain", network_type="$network_type", component="$component", service="$service"}, service_id)`), + query.Sort(query.NumericalAsc), + ), + } +} + +func generalInfoRow(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.Row( + "General CL Cluster Info", + row.WithTable( + "List Nodes", + table.Span(12), + table.HideColumn("Time"), + table.HideColumn("Value"), + table.DataSource(p.PrometheusDataSource), + table.WithPrometheusTarget( + `max(up{`+p.PlatformOpts.LabelQuery+`}) by (env, cluster, blockchain, product, network_type, network, version, team, component, service)`, + prometheus.Legend(""), + prometheus.Format("table"), + prometheus.Instant(), + ), + ), + row.WithTimeSeries( + "Uptime", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Max(1), + axis.Max(0), + axis.Unit("bool"), + axis.Label("Alive"), + ), + timeseries.WithPrometheusTarget( + `up{`+p.PlatformOpts.LabelQuery+`}`, + //prometheus.Legend(""), + prometheus.Legend("Team: {{team}} env: {{env}} cluster: {{cluster}} namespace: {{namespace}} job: {{job}} blockchain: {{blockchain}} product: {{product}} networkType: {{network_type}} component: {{component}} service: {{service}}"), + ), + ), + row.WithTimeSeries( + "Service Components Health by Service", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.Legend(timeseries.ToTheRight), + timeseries.WithPrometheusTarget( + `health{`+p.PlatformOpts.LabelQuery+`service_id=~"${service_id}"}`, + prometheus.Legend("{{service_id}}"), + ), + ), + row.WithTimeSeries( + "Service Components Health Avg by Service", + timeseries.Span(12), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.Legend(timeseries.ToTheRight), + timeseries.WithPrometheusTarget( + `avg(avg_over_time(health{`+p.PlatformOpts.LabelQuery+`service_id=~"${service_id}"}[$interval])) by (service_id, version, service, cluster, env)`, + prometheus.Legend("{{service_id}}"), + ), + ), + row.WithStat( + "Service Components Health Avg by Service", + stat.Span(12), + stat.Height("200px"), + stat.DataSource(p.PrometheusDataSource), + stat.Text(stat.TextValueAndName), + stat.Orientation(stat.OrientationVertical), + stat.SparkLine(), + stat.TitleFontSize(8), + stat.ValueFontSize(12), + stat.WithPrometheusTarget( + `avg(avg_over_time(health{`+p.PlatformOpts.LabelQuery+`service_id=~"${service_id}"}[$interval])) by (service_id, version, service, cluster, env)`, + prometheus.Legend("{{service_id}}"), + ), + stat.AbsoluteThresholds([]stat.ThresholdStep{ + {Color: "#FF0000", Value: float64Ptr(0.0)}, + {Color: "#FF0000", Value: float64Ptr(0.8)}, + {Color: "#008000", Value: float64Ptr(1.0)}, + }), + ), + ), + } +} + +func New(p Props) []dashboard.Option { + opts := vars(p) + opts = append(opts, generalInfoRow(p)...) + return opts +} + +func float64Ptr(input float64) *float64 { + return &input +} diff --git a/dashboard-lib/core-node-components/platform.go b/dashboard-lib/core-node-components/platform.go new file mode 100644 index 00000000000..9d85cf82c77 --- /dev/null +++ b/dashboard-lib/core-node-components/platform.go @@ -0,0 +1,29 @@ +package core_node_components + +type PlatformOpts struct { + // Platform is infrastructure deployment platform: docker or k8s + Platform string + LabelFilters map[string]string + LabelFilter string + LegendString string + LabelQuery string +} + +// PlatformPanelOpts generate different queries for "docker" and "k8s" deployment platforms +func PlatformPanelOpts() PlatformOpts { + po := PlatformOpts{ + LabelFilters: map[string]string{ + "env": `=~"${env}"`, + "cluster": `=~"${cluster}"`, + "blockchain": `=~"${blockchain}"`, + "product": `=~"${product}"`, + "network_type": `=~"${network_type}"`, + "component": `=~"${component}"`, + "service": `=~"${service}"`, + }, + } + for key, value := range po.LabelFilters { + po.LabelQuery += key + value + ", " + } + return po +} diff --git a/go.mod b/go.mod index 5a872c77e76..ff9993618c1 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/ethereum/go-ethereum v1.13.8 github.com/fatih/color v1.16.0 github.com/fxamacker/cbor/v2 v2.5.0 - github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 + github.com/gagliardetto/solana-go v1.8.4 github.com/getsentry/sentry-go v0.19.0 github.com/gin-contrib/cors v1.5.0 github.com/gin-contrib/expvar v0.0.1 @@ -29,7 +29,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-webauthn/webauthn v0.9.4 github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.5.0 github.com/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.2.2 github.com/gorilla/websocket v1.5.1 @@ -72,17 +72,17 @@ 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.20240415164156-8872a8f311cb - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 - github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 + github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wsrpc v0.7.2 + github.com/smartcontractkit/wsrpc v0.8.1 github.com/spf13/cast v1.6.0 github.com/stretchr/testify v1.9.0 github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a @@ -113,14 +113,6 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) -require ( - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect @@ -140,12 +132,13 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect @@ -187,7 +180,7 @@ require ( github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gagliardetto/binary v0.7.1 // indirect + github.com/gagliardetto/binary v0.7.7 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect @@ -260,6 +253,7 @@ require ( github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -296,6 +290,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.15.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect + github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/supranational/blst v0.3.11 // indirect @@ -313,12 +308,14 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect go.dedis.ch/protobuf v1.0.11 // indirect go.etcd.io/bbolt v1.3.7 // indirect + go.mongodb.org/mongo-driver v1.15.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect @@ -340,6 +337,7 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index ce6477a21e3..1f94c3dfc9f 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,6 @@ github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= @@ -411,13 +409,12 @@ github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADi github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= -github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI= -github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= +github.com/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY= +github.com/gagliardetto/binary v0.7.7/go.mod h1:mUuay5LL8wFVnIlecHakSZMvcdqfs+CsotR5n77kyjM= github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 h1:q2IztKyRQUxJ6abXRsawaBtvDFvM+szj4jDqV4od1gs= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY= +github.com/gagliardetto/solana-go v1.8.4 h1:vmD/JmTlonyXGy39bAo0inMhmbdAwV7rXZtLDMZeodE= +github.com/gagliardetto/solana-go v1.8.4/go.mod h1:i+7aAyNDTHG0jK8GZIBSI4OVvDqkt2Qx+LklYclRNG8= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= @@ -572,6 +569,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -629,10 +627,9 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -997,6 +994,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= @@ -1182,16 +1180,16 @@ 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.20240415164156-8872a8f311cb h1:yLDt5cQWRwcFM5VEdSTbc3vDrYrxYqBjSvyTMU/o8s4= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240415164156-8872a8f311cb/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 h1:elDIBChe7ByPNvCyrSjMLTPKrgY+sKgzzlWe2p3wokY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9/go.mod h1:GTDBbovHUSAUk+fuGIySF2A/whhdtHGaWmU61BoERks= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 h1:MvaNzuaQh1vX4CAYLM8qFd99cf0ZF1JNwtDZtLU7WvU= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92/go.mod h1:uATrrJ8IsuBkOBJ46USuf73gz9gZy5k5bzGE5/ji/rc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab h1:Ct1oUlyn03HDUVdFHJqtRGRUujMqdoMzvf/Cjhe30Ag= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab/go.mod h1:RPUY7r8GxgzXxS1ijtU1P/fpJomOXztXgUbEziNmbCA= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 h1:jc4ab5QrKZfkICyxJysCt7mSExuSPbePjgZsnJR3nRQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58/go.mod h1:oV5gIuSKrPEcjQ6uB6smBsm5kXHxyydVLNyAs4V9CoQ= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= @@ -1200,14 +1198,14 @@ github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+ github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= -github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= +github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= +github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1238,6 +1236,8 @@ github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 h1:ZqpS7rAhhKD7S7DnrpEdrnW1/gZcv82ytpMviovkli4= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1284,6 +1284,7 @@ github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -1332,6 +1333,9 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1348,6 +1352,7 @@ github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dz github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA= github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= @@ -1377,6 +1382,9 @@ go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYr go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1433,7 +1441,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1458,11 +1466,12 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= @@ -1556,8 +1565,8 @@ golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1655,7 +1664,6 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1759,7 +1767,6 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= diff --git a/integration-tests/actions/vrf/common/errors.go b/integration-tests/actions/vrf/common/errors.go index 287403ecfdf..f174609823f 100644 --- a/integration-tests/actions/vrf/common/errors.go +++ b/integration-tests/actions/vrf/common/errors.go @@ -1,6 +1,7 @@ package common const ( + ErrGenericFormat = "%s, err %w" ErrNodePrimaryKey = "error getting node's primary ETH key" ErrNodeNewTxKey = "error creating node's EVM transaction key" ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" diff --git a/integration-tests/actions/vrf/common/logging_helpers.go b/integration-tests/actions/vrf/common/logging_helpers.go new file mode 100644 index 00000000000..f9c8a031678 --- /dev/null +++ b/integration-tests/actions/vrf/common/logging_helpers.go @@ -0,0 +1,129 @@ +package common + +import ( + "fmt" + "math/big" + + "github.com/rs/zerolog" + + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" +) + +func LogSubDetails( + l zerolog.Logger, + subscription contracts.Subscription, + subID string, + coordinator contracts.Coordinator, +) { + log := l.Info(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). + Str("Subscription ID", subID). + Str("Subscription Owner", subscription.SubOwner.String()). + Interface("Subscription Consumers", subscription.Consumers) + if subscription.NativeBalance != nil { + log = log.Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)) + } + log.Msg("Subscription Data") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.Coordinator, + randomWordsRequestedEvent *contracts.CoordinatorRandomWordsRequested, + isNativeBilling bool, +) { + l.Info(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). + Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.Coordinator, + randomWordsFulfilledEvent *contracts.CoordinatorRandomWordsFulfilled, + isNativeBilling bool, +) { + l.Info(). + Bool("Native Billing", isNativeBilling). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Subscription ID", randomWordsFulfilledEvent.SubId). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogFulfillmentDetailsLinkBilling( + l zerolog.Logger, + wrapperConsumerJuelsBalanceBeforeRequest *big.Int, + wrapperConsumerJuelsBalanceAfterRequest *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *contracts.CoordinatorRandomWordsFulfilled, +) { + l.Info(). + Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Fulfilment Details For Link Billing") +} + +func LogFulfillmentDetailsNativeBilling( + l zerolog.Logger, + wrapperConsumerBalanceBeforeRequestWei *big.Int, + wrapperConsumerBalanceAfterRequestWei *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *contracts.CoordinatorRandomWordsFulfilled, +) { + l.Info(). + Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). + Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). + Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Request Fulfilment Details For Native Billing") +} + +func LogRandomWordsForcedEvent( + l zerolog.Logger, + vrfOwner contracts.VRFOwner, + randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced, +) { + l.Debug(). + Str("VRFOwner", vrfOwner.Address()). + Uint64("Sub ID", randomWordsForcedEvent.SubId). + Str("TX Hash", randomWordsForcedEvent.Raw.TxHash.String()). + Str("Request ID", randomWordsForcedEvent.RequestId.String()). + Str("Sender", randomWordsForcedEvent.Sender.String()). + Msg("RandomWordsForced Event (TX metadata)") +} diff --git a/integration-tests/actions/vrf/vrfv2/contract_steps.go b/integration-tests/actions/vrf/vrfv2/contract_steps.go index 46b84eb836b..fef780b695b 100644 --- a/integration-tests/actions/vrf/vrfv2/contract_steps.go +++ b/integration-tests/actions/vrf/vrfv2/contract_steps.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/shopspring/decimal" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" @@ -212,7 +213,7 @@ func SetupVRFV2Contracts( *vrfv2Config.MaxGasLimitCoordinatorConfig, *vrfv2Config.StalenessSeconds, *vrfv2Config.GasAfterPaymentCalculation, - big.NewInt(*vrfv2Config.FallbackWeiPerUnitLink), + decimal.RequireFromString(*vrfv2Config.FallbackWeiPerUnitLink).BigInt(), vrfCoordinatorV2FeeConfig, ) if err != nil { @@ -452,7 +453,7 @@ func FundVRFCoordinatorV2Subscription( func DirectFundingRequestRandomnessAndWaitForFulfillment( l zerolog.Logger, consumer contracts.VRFv2WrapperLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, + coordinator contracts.Coordinator, subID uint64, vrfv2KeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, @@ -461,7 +462,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { +) (*contracts.CoordinatorRandomWordsFulfilled, error) { logRandRequest( l, consumer.Address(), @@ -496,7 +497,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( func RequestRandomnessAndWaitForFulfillment( l zerolog.Logger, consumer contracts.VRFv2LoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, + coordinator contracts.Coordinator, subID uint64, vrfKeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, @@ -505,7 +506,7 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { +) (*contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsRequestedEvent, err := RequestRandomness( l, consumer, @@ -536,7 +537,7 @@ func RequestRandomnessAndWaitForFulfillment( func RequestRandomness( l zerolog.Logger, consumer contracts.VRFv2LoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, + coordinator contracts.Coordinator, subID uint64, vrfKeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, @@ -544,7 +545,7 @@ func RequestRandomness( numberOfWords uint32, randomnessRequestCountPerRequest uint16, randomnessRequestCountPerRequestDeviation uint16, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { +) (*contracts.CoordinatorRandomWordsRequested, error) { logRandRequest( l, consumer.Address(), @@ -569,7 +570,7 @@ func RequestRandomness( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false) return randomWordsRequestedEvent, err } @@ -577,7 +578,7 @@ func RequestRandomness( func RequestRandomnessWithForceFulfillAndWaitForFulfillment( l zerolog.Logger, consumer contracts.VRFv2LoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, + coordinator contracts.Coordinator, vrfOwner contracts.VRFOwner, vrfv2KeyData *vrfcommon.VRFKeyData, minimumConfirmations uint16, @@ -588,9 +589,10 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( subTopUpAmount *big.Int, linkAddress common.Address, randomWordsFulfilledEventTimeout time.Duration, -) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { +) (*contracts.CoordinatorConfigSet, *contracts.CoordinatorRandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfv2KeyData.KeyHash) - _, err := consumer.RequestRandomWordsWithForceFulfill( + randomWordsRequestedEvent, err := consumer.RequestRandomWordsWithForceFulfill( + coordinator, vrfv2KeyData.KeyHash, minimumConfirmations, callbackGasLimit, @@ -603,20 +605,11 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2KeyData.KeyHash}, - nil, - []common.Address{common.HexToAddress(consumer.Address())}, - time.Minute*1, - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) - } - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, false) errorChannel := make(chan error) - configSetEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) - randWordsFulfilledEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled) + configSetEventChannel := make(chan *contracts.CoordinatorConfigSet) + randWordsFulfilledEventChannel := make(chan *contracts.CoordinatorRandomWordsFulfilled) randWordsForcedEventChannel := make(chan *vrf_owner.VRFOwnerRandomWordsForced) go func() { @@ -632,8 +625,10 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( go func() { randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{randomWordsRequestedEvent.RequestId}, + Timeout: randomWordsFulfilledEventTimeout, + }, ) if err != nil { l.Error().Err(err).Msg("error waiting for RandomWordsFulfilledEvent") @@ -656,8 +651,8 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( randWordsForcedEventChannel <- randomWordsForcedEvent }() - var configSetEvent *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet - var randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled + var configSetEvent *contracts.CoordinatorConfigSet + var randomWordsFulfilledEvent *contracts.CoordinatorRandomWordsFulfilled var randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced for i := 0; i < 3; i++ { select { @@ -665,9 +660,9 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( return nil, nil, nil, err case configSetEvent = <-configSetEventChannel: case randomWordsFulfilledEvent = <-randWordsFulfilledEventChannel: - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false) case randomWordsForcedEvent = <-randWordsForcedEventChannel: - LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) + vrfcommon.LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) case <-time.After(randomWordsFulfilledEventTimeout): err = fmt.Errorf("timeout waiting for ConfigSet, RandomWordsFulfilled and RandomWordsForced events") } @@ -676,19 +671,21 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( } func WaitRandomWordsFulfilledEvent( - coordinator contracts.VRFCoordinatorV2, + coordinator contracts.Coordinator, requestId *big.Int, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { +) (*contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{requestId}, - randomWordsFulfilledEventTimeout, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{requestId}, + Timeout: randomWordsFulfilledEventTimeout, + }, ) if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, false) return randomWordsFulfilledEvent, err } diff --git a/integration-tests/actions/vrf/vrfv2/logging_helpers.go b/integration-tests/actions/vrf/vrfv2/logging_helpers.go index 82c45267aaf..248eebf45f1 100644 --- a/integration-tests/actions/vrf/vrfv2/logging_helpers.go +++ b/integration-tests/actions/vrf/vrfv2/logging_helpers.go @@ -4,73 +4,8 @@ import ( "fmt" "github.com/rs/zerolog" - - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" ) -func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2.GetSubscription, subID uint64, coordinator contracts.VRFCoordinatorV2) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). - Uint64("Subscription ID", subID). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") -} - -func LogRandomnessRequestedEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2, - randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, -) { - l.Info(). - Str("Coordinator", coordinator.Address()). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Uint64("Subscription ID", randomWordsRequestedEvent.SubId). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). - Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2, - randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, -) { - l.Info(). - Str("Coordinator", coordinator.Address()). - Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogRandomWordsForcedEvent( - l zerolog.Logger, - vrfOwner contracts.VRFOwner, - randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced, -) { - l.Debug(). - Str("VRFOwner", vrfOwner.Address()). - Uint64("Sub ID", randomWordsForcedEvent.SubId). - Str("TX Hash", randomWordsForcedEvent.Raw.TxHash.String()). - Str("Request ID", randomWordsForcedEvent.RequestId.String()). - Str("Sender", randomWordsForcedEvent.Sender.String()). - Msg("RandomWordsForced Event (TX metadata)") -} - func logRandRequest( l zerolog.Logger, consumer string, diff --git a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go index 5df33a6d997..143b1e2cd9b 100644 --- a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/shopspring/decimal" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" @@ -19,8 +20,6 @@ import ( tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" ) func DeployVRFV2_5Contracts( @@ -29,15 +28,15 @@ func DeployVRFV2_5Contracts( ) (*vrfcommon.VRFContracts, error) { bhs, err := contractDeployer.DeployBlockhashStore() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrDeployBlockHashStore, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } batchBHS, err := contractDeployer.DeployBatchBlockhashStore(bhs.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBatchBlockHashStore, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrDeployBatchBlockHashStore, err) } err = chainClient.WaitForEvents() if err != nil { @@ -45,11 +44,11 @@ func DeployVRFV2_5Contracts( } coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrDeployCoordinator, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return &vrfcommon.VRFContracts{ CoordinatorV2Plus: coordinator, @@ -64,7 +63,7 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord for i := 1; i <= consumerContractsAmount; i++ { loadTestConsumer, err := contractDeployer.DeployVRFv2PlusLoadTestConsumer(coordinator.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAdvancedConsumer, err) } consumers = append(consumers, loadTestConsumer) } @@ -78,14 +77,14 @@ func VRFV2_5RegisterProvingKey( ) (vrfcommon.VRFEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( provingKey, gasLaneMaxGas, ) if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRegisterProvingKey, err) } return provingKey, nil } @@ -93,16 +92,18 @@ func VRFV2_5RegisterProvingKey( func VRFV2PlusUpgradedVersionRegisterProvingKey( vrfKey *client.VRFKey, coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + gasLaneMaxGasPrice uint64, ) (vrfcommon.VRFEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( provingKey, + gasLaneMaxGasPrice, ) if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRegisterProvingKey, err) } return provingKey, nil } @@ -116,11 +117,11 @@ func FundVRFCoordinatorV2_5Subscription( ) error { encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrABIEncodingFunding, err) } _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrSendingLinkToken, err) } return chainClient.WaitForEvents() } @@ -169,7 +170,7 @@ func CreateFundSubsAndAddConsumers( err = evmClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return subIDs, nil } @@ -194,7 +195,7 @@ func CreateSubsAndFund( err = evmClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } err = FundSubscriptions( env, @@ -237,7 +238,7 @@ func AddConsumersToSubs( for _, consumer := range consumers { err := coordinator.AddConsumer(subID, consumer.Address()) if err != nil { - return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAddConsumerToSub, err) } } } @@ -247,7 +248,7 @@ func AddConsumersToSubs( func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { tx, err := coordinator.CreateSubscription() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrCreateVRFSubscription, err) } evmClient, err := env.GetEVMClient(chainID) if err != nil { @@ -255,12 +256,12 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordi } err = evmClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } receipt, err := evmClient.GetTxReceipt(tx.Hash()) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } //SubscriptionsCreated Log should be emitted with the subscription ID @@ -291,18 +292,18 @@ func FundSubscriptions( amountWei, ) if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, ErrFundSubWithNativeToken, err) } //Link Billing amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, evmClient, subID, amountJuels) if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrFundSubWithLinkToken, err) } } err = evmClient.WaitForEvents() if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return nil } @@ -310,11 +311,11 @@ func FundSubscriptions( func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrLinkTotalBalance, err) } nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrNativeTokenBalance, err) } return } @@ -322,24 +323,24 @@ func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2Pl func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrLinkTotalBalance, err) } nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrNativeTokenBalance, err) } return } -func RequestRandomnessAndWaitForRequestedEvent( +func RequestRandomness( consumer contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, + coordinator contracts.Coordinator, vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) { +) (*contracts.CoordinatorRandomWordsRequested, error) { LogRandRequest( l, consumer.Address(), @@ -349,152 +350,59 @@ func RequestRandomnessAndWaitForRequestedEvent( vrfKeyData.KeyHash, config, ) - ch := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested) - errorChannel := make(chan error) - go func() { - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, - subID, - *config.MinimumConfirmations, - *config.CallbackGasLimit, - isNativeBilling, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - l.Error().Err(err).Msg(err.Error()) - errorChannel <- err - } - }() - go func() { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumer.Address())}, - time.Minute*1, - ) - if err != nil { - l.Error().Err(err).Msg("error waiting for RandomnessRequested events") - errorChannel <- err - } - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) - ch <- randomWordsRequestedEvent - }() - for { - select { - case err := <-errorChannel: - return nil, err - case event := <-ch: - return event, nil - case <-time.After(config.RandomWordsFulfilledEventTimeout.Duration): - return nil, fmt.Errorf("timeout waiting for RandomnessRequested events") - } - } -} - -func RequestRandomnessAndWaitForFulfillment( - consumer contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - LogRandRequest( - l, - consumer.Address(), - coordinator.Address(), + randomWordsRequestedEvent, err := consumer.RequestRandomness( + coordinator, + vrfKeyData.KeyHash, subID, + *config.MinimumConfirmations, + *config.CallbackGasLimit, isNativeBilling, - vrfKeyData.KeyHash, - config, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, ) - ch := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) - errorChannel := make(chan error) - go func() { - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, - subID, - *config.MinimumConfirmations, - *config.CallbackGasLimit, - isNativeBilling, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - l.Error().Err(err).Msg(err.Error()) - errorChannel <- err - } - }() - go func() { - fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( - consumer.Address(), - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) - if err != nil { - l.Error().Err(err).Msg("error waiting for RandomnessRequested and RandomWordsFulfilled events") - errorChannel <- err - } - ch <- fulfillmentEvents - }() - for { - select { - case err := <-errorChannel: - return nil, err - case fulfillmentEvent := <-ch: - return fulfillmentEvent, nil - case <-time.After(config.RandomWordsFulfilledEventTimeout.Duration): - return nil, fmt.Errorf("timeout waiting for RandomnessRequested and RandomWordsFulfilled events") - } + if err != nil { + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRequestRandomness, err) } + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + + return randomWordsRequestedEvent, err } -func RequestRandomnessAndWaitForFulfillmentUpgraded( +func RequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + coordinator contracts.Coordinator, vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - LogRandRequest( - l, - consumer.Address(), - coordinator.Address(), +) (*contracts.CoordinatorRandomWordsFulfilled, error) { + randomWordsRequestedEvent, err := RequestRandomness( + consumer, + coordinator, + vrfKeyData, subID, isNativeBilling, - vrfKeyData.KeyHash, config, - ) - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, - subID, - *config.MinimumConfirmations, - *config.CallbackGasLimit, - isNativeBilling, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, + l, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) + return nil, err } - return WaitForRequestAndFulfillmentEventsUpgraded( - consumer.Address(), + randomWordsFulfilledEvent, err := WaitRandomWordsFulfilledEvent( coordinator, - vrfKeyData, + randomWordsRequestedEvent.RequestId, subID, isNativeBilling, config.RandomWordsFulfilledEventTimeout.Duration, l, ) + if err != nil { + return nil, err + } + return randomWordsFulfilledEvent, nil + } func DeployVRFV2PlusDirectFundingContracts( @@ -509,11 +417,11 @@ func DeployVRFV2PlusDirectFundingContracts( vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address(), wrapperSubId) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployWrapper, err) } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, vrfv2PlusWrapper, consumerContractsAmount) @@ -522,74 +430,71 @@ func DeployVRFV2PlusDirectFundingContracts( } err = chainClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil } -func WrapperRequestRandomness( - consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinatorAddress string, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger) (string, error) { +func WrapperRequestRandomness(consumer contracts.VRFv2PlusWrapperLoadTestConsumer, coordinator contracts.Coordinator, vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger) (*contracts.CoordinatorRandomWordsRequested, string, error) { LogRandRequest( l, consumer.Address(), - coordinatorAddress, + coordinator.Address(), subID, isNativeBilling, vrfKeyData.KeyHash, config, ) + var randomWordsRequestedEvent *contracts.CoordinatorRandomWordsRequested + var err error if isNativeBilling { - _, err := consumer.RequestRandomnessNative( + randomWordsRequestedEvent, err = consumer.RequestRandomnessNative( + coordinator, *config.MinimumConfirmations, *config.CallbackGasLimit, *config.NumberOfWords, *config.RandomnessRequestCountPerRequest, ) if err != nil { - return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) + return nil, "", fmt.Errorf(vrfcommon.ErrGenericFormat, ErrRequestRandomnessDirectFundingNativePayment, err) } } else { - _, err := consumer.RequestRandomness( + randomWordsRequestedEvent, err = consumer.RequestRandomness( + coordinator, *config.MinimumConfirmations, *config.CallbackGasLimit, *config.NumberOfWords, *config.RandomnessRequestCountPerRequest, ) if err != nil { - return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) + return nil, "", fmt.Errorf(vrfcommon.ErrGenericFormat, ErrRequestRandomnessDirectFundingLinkPayment, err) } } + vrfcommon.LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) wrapperAddress, err := consumer.GetWrapper(context.Background()) if err != nil { - return "", fmt.Errorf("error getting wrapper address, err: %w", err) + return nil, "", fmt.Errorf("error getting wrapper address, err: %w", err) } - return wrapperAddress.Hex(), nil + return randomWordsRequestedEvent, wrapperAddress.Hex(), nil } func DirectFundingRequestRandomnessAndWaitForFulfillment( consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, + coordinator contracts.Coordinator, vrfKeyData *vrfcommon.VRFKeyData, subID *big.Int, isNativeBilling bool, config *vrfv2plus_config.General, l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, +) (*contracts.CoordinatorRandomWordsFulfilled, error) { + randomWordsRequestedEvent, _, err := WrapperRequestRandomness(consumer, coordinator, vrfKeyData, subID, isNativeBilling, config, l) if err != nil { return nil, fmt.Errorf("error getting wrapper address, err: %w", err) } - return WaitForRequestAndFulfillmentEvents( - wrapperAddress, + return WaitRandomWordsFulfilledEvent( coordinator, - vrfKeyData, + randomWordsRequestedEvent.RequestId, subID, isNativeBilling, config.RandomWordsFulfilledEventTimeout.Duration, @@ -597,95 +502,26 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( ) } -func DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( - consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, - isNativeBilling, config, l) - if err != nil { - return nil, fmt.Errorf("error getting wrapper address, err: %w", err) - } - return WaitForRequestAndFulfillmentEventsUpgraded( - wrapperAddress, - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) -} - -func WaitForRequestAndFulfillmentEvents( - consumerAddress string, - coordinator contracts.VRFCoordinatorV2_5, - vrfKeyData *vrfcommon.VRFKeyData, +func WaitRandomWordsFulfilledEvent( + coordinator contracts.Coordinator, + requestId *big.Int, subID *big.Int, isNativeBilling bool, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) - } - - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) - +) (*contracts.CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) - } - - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) - return randomWordsFulfilledEvent, err -} - -func WaitForRequestAndFulfillmentEventsUpgraded( - consumerAddress string, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, + contracts.RandomWordsFulfilledEventFilter{ + SubIDs: []*big.Int{subID}, + RequestIds: []*big.Int{requestId}, + Timeout: randomWordsFulfilledEventTimeout, + }, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) } - LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent, isNativeBilling) - - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) - } - LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) return randomWordsFulfilledEvent, err } @@ -694,7 +530,7 @@ func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer for i := 1; i <= consumerContractsAmount; i++ { loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapper.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAdvancedConsumer, err) } consumers = append(consumers, loadTestConsumer) } @@ -716,7 +552,7 @@ func SetupVRFV2PlusContracts( } vrfContracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, evmClient) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployVRFV2_5Contracts, err) } vrfContracts.LinkToken = linkToken vrfContracts.MockETHLINKFeed = mockNativeLINKFeed @@ -727,24 +563,24 @@ func SetupVRFV2PlusContracts( *configGeneral.MaxGasLimitCoordinatorConfig, *configGeneral.StalenessSeconds, *configGeneral.GasAfterPaymentCalculation, - big.NewInt(*configGeneral.FallbackWeiPerUnitLink), + decimal.RequireFromString(*configGeneral.FallbackWeiPerUnitLink).BigInt(), *configGeneral.FulfillmentFlatFeeNativePPM, *configGeneral.FulfillmentFlatFeeLinkDiscountPPM, *configGeneral.NativePremiumPercentage, *configGeneral.LinkPremiumPercentage, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrSetVRFCoordinatorConfig, err) } l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Link and ETH/LINK feed") err = vrfContracts.CoordinatorV2Plus.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrSetLinkNativeLinkFeed, err) } err = evmClient.WaitForEvents() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return vrfContracts, nil @@ -762,15 +598,12 @@ func SetupNewConsumersAndSubs( ) ([]contracts.VRFv2PlusLoadTestConsumer, []*big.Int, error) { consumers, err := DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, consumerContractsAmount) if err != nil { - if err != nil { - return nil, nil, fmt.Errorf("err: %w", err) - } + return nil, nil, fmt.Errorf("err: %w", err) } evmClient, err := env.GetEVMClient(chainID) if err != nil { return nil, nil, err } - err = evmClient.WaitForEvents() if err != nil { return nil, nil, fmt.Errorf("%s, err: %w", vrfcommon.ErrWaitTXsComplete, err) diff --git a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go index 995af9ee76c..b613298f1fd 100644 --- a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go +++ b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go @@ -6,165 +6,12 @@ import ( "github.com/rs/zerolog" - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/contracts" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" ) -func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). - Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.SubOwner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") -} - -func LogRandomnessRequestedEventUpgraded( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - randomWordsRequestedEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, - isNativeBilling bool, -) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEventUpgraded( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - randomWordsFulfilledEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, - isNativeBilling bool, -) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogRandomnessRequestedEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2_5, - randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, - isNativeBilling bool, -) { - l.Info(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). - Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2_5, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, - isNativeBilling bool, -) { - l.Info(). - Bool("Native Billing", isNativeBilling). - Str("Coordinator", coordinator.Address()). - Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubId.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *vrfcommon.VRFContracts) { - l.Info(). - Str("Subscription ID", migrationCompletedEvent.SubId.String()). - Str("Migrated From Coordinator", vrfv2PlusContracts.CoordinatorV2Plus.Address()). - Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). - Msg("MigrationCompleted Event") -} - -func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { - l.Info(). - Str("New Coordinator", newCoordinator.Address()). - Str("Subscription ID", subID.String()). - Str("Juels Balance", migratedSubscription.Balance.String()). - Str("Native Token Balance", migratedSubscription.NativeBalance.String()). - Str("Subscription Owner", migratedSubscription.SubOwner.String()). - Interface("Subscription Consumers", migratedSubscription.Consumers). - Msg("Subscription Data After Migration to New Coordinator") -} - -func LogFulfillmentDetailsLinkBilling( - l zerolog.Logger, - wrapperConsumerJuelsBalanceBeforeRequest *big.Int, - wrapperConsumerJuelsBalanceAfterRequest *big.Int, - consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, -) { - l.Info(). - Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). - Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). - Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Fulfilment Details For Link Billing") -} - -func LogFulfillmentDetailsNativeBilling( - l zerolog.Logger, - wrapperConsumerBalanceBeforeRequestWei *big.Int, - wrapperConsumerBalanceAfterRequestWei *big.Int, - consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, -) { - l.Info(). - Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). - Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). - Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Request Fulfilment Details For Native Billing") -} - func LogRandRequest( l zerolog.Logger, consumer string, @@ -186,3 +33,22 @@ func LogRandRequest( Uint16("RandomnessRequestCountPerRequestDeviation", *config.RandomnessRequestCountPerRequestDeviation). Msg("Requesting randomness") } + +func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, coordinator contracts.Coordinator) { + l.Info(). + Str("Subscription ID", migrationCompletedEvent.SubId.String()). + Str("Migrated From Coordinator", coordinator.Address()). + Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). + Msg("MigrationCompleted Event") +} + +func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.Coordinator, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { + l.Info(). + Str("New Coordinator", newCoordinator.Address()). + Str("Subscription ID", subID.String()). + Str("Juels Balance", migratedSubscription.Balance.String()). + Str("Native Token Balance", migratedSubscription.NativeBalance.String()). + Str("Subscription Owner", migratedSubscription.SubOwner.String()). + Interface("Subscription Consumers", migratedSubscription.Consumers). + Msg("Subscription Data After Migration to New Coordinator") +} diff --git a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go index 3ceb4b6f9dd..0b7be600cc2 100644 --- a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/shopspring/decimal" "golang.org/x/sync/errgroup" "github.com/ethereum/go-ethereum/common" @@ -39,7 +40,7 @@ func CreateVRFV2PlusJob( } ost, err := os.String() if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrParseJob, err) } job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ @@ -57,7 +58,7 @@ func CreateVRFV2PlusJob( RequestTimeout: vrfJobSpecConfig.RequestTimeout, }) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) + return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrCreatingVRFv2PlusJob, err) } return job, nil @@ -100,11 +101,11 @@ func SetupVRFV2_5Environment( l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Registering Proving Key") provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfContracts.CoordinatorV2Plus, uint64(assets.GWei(*configGeneral.CLNodeMaxGasPriceGWei).Int64())) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) + return nil, nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRegisteringProvingKey, err) } keyHash, err := vrfContracts.CoordinatorV2Plus.HashOfKey(ctx, provingKey) if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) + return nil, nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrCreatingProvingKeyHash, err) } evmClient, err := env.GetEVMClient(chainID) @@ -124,7 +125,7 @@ func SetupVRFV2_5Environment( } err = evmClient.WaitForEvents() if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings @@ -219,7 +220,7 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *v vrfJobSpecConfig, ) if err != nil { - return fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, ErrCreateVRFV2PlusJobs, err) } vrfNode.Job = job @@ -233,7 +234,7 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *v l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = vrfNode.CLNode.Restart(nodeConfig) if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) + return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRestartCLNode, err) } return nil } @@ -278,7 +279,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } // once the wrapper is deployed, wrapper address will become consumer of external EOA subscription @@ -289,22 +290,21 @@ func SetupVRFV2PlusWrapperEnvironment( err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } - err = wrapperContracts.VRFV2PlusWrapper.SetConfig( *vrfv2PlusConfig.WrapperGasOverhead, - *vrfv2PlusConfig.CoordinatorGasOverhead, + *vrfv2PlusConfig.CoordinatorGasOverheadNative, + *vrfv2PlusConfig.CoordinatorGasOverheadLink, *vrfv2PlusConfig.CoordinatorGasOverheadPerWord, - //todo - introduce separate config for Wrapper Premium Percentage - *vrfv2PlusConfig.NativePremiumPercentage, - *vrfv2PlusConfig.LinkPremiumPercentage, + *vrfv2PlusConfig.CoordinatorNativePremiumPercentage, + *vrfv2PlusConfig.CoordinatorLinkPremiumPercentage, keyHash, *vrfv2PlusConfig.WrapperMaxNumberOfWords, *vrfv2PlusConfig.StalenessSeconds, - big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), - *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + decimal.RequireFromString(*vrfv2PlusConfig.FallbackWeiPerUnitLink).BigInt(), *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + *vrfv2PlusConfig.FulfillmentFlatFeeLinkDiscountPPM, ) if err != nil { return nil, nil, err @@ -312,7 +312,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } //fund sub @@ -323,7 +323,7 @@ func SetupVRFV2PlusWrapperEnvironment( err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } err = FundSubscriptions( @@ -349,7 +349,7 @@ func SetupVRFV2PlusWrapperEnvironment( } err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } //fund consumer with Eth @@ -359,7 +359,7 @@ func SetupVRFV2PlusWrapperEnvironment( } err = evmClient.WaitForEvents() if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err) } return wrapperContracts, wrapperSubID, nil } diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 4dff9c98b61..aaccbad0602 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -60,23 +60,23 @@ type VRFCoordinatorV2 interface { CreateSubscription() (*types.Transaction, error) AddConsumer(subId uint64, consumerAddress string) error Address() string - GetSubscription(ctx context.Context, subID uint64) (vrf_coordinator_v2.GetSubscription, error) + 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) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) - ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) + ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) ParseLog(log types.Log) (generated.AbigenLog, error) CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) FindSubscriptionID(subID uint64) (uint64, error) - WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, 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) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) + WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) OracleWithdraw(recipient common.Address, amount *big.Int) error } @@ -109,7 +109,7 @@ type VRFCoordinatorV2_5 interface { 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) (vrf_coordinator_v2_5.GetSubscription, 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) Withdraw(recipient common.Address) error @@ -119,9 +119,10 @@ type VRFCoordinatorV2_5 interface { 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(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) - WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) + WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) + ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) + WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) } type VRFCoordinatorV2PlusUpgradedVersion interface { @@ -142,6 +143,7 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { ) error RegisterProvingKey( publicProvingKey [2]*big.Int, + gasLaneMaxGasPrice uint64, ) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) CreateSubscription() error @@ -155,9 +157,10 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { GetSubscription(ctx context.Context, subID *big.Int) (vrf_v2plus_upgraded_version.GetSubscription, error) GetActiveSubscriptionIds(ctx context.Context, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) FindSubscriptionID() (*big.Int, error) - WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) + WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMigrationCompleted, error) - WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, error) + ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) + WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) } type VRFV2Wrapper interface { @@ -168,7 +171,19 @@ type VRFV2Wrapper interface { type VRFV2PlusWrapper interface { Address() string - SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, coordinatorGasOverheadPerWord uint16, wrapperNativePremiumPercentage uint8, wrapperLinkPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeNativePPM uint32, fulfillmentFlatFeeLinkDiscountPPM uint32) error + SetConfig( + wrapperGasOverhead uint32, + coordinatorGasOverheadNative uint32, + coordinatorGasOverheadLink uint32, + coordinatorGasOverheadPerWord uint16, + wrapperNativePremiumPercentage uint8, + wrapperLinkPremiumPercentage uint8, + keyHash [32]byte, maxNumWords uint8, + stalenessSeconds uint32, + fallbackWeiPerUnitLink *big.Int, + fulfillmentFlatFeeNativePPM uint32, + fulfillmentFlatFeeLinkDiscountPPM uint32, + ) error GetSubID(ctx context.Context) (*big.Int, error) Coordinator(ctx context.Context) (common.Address, error) } @@ -211,15 +226,16 @@ type VRFv2Consumer interface { type VRFv2LoadTestConsumer interface { Address() string RequestRandomness( - coordinator VRFCoordinatorV2, + coordinator Coordinator, keyHash [32]byte, subID uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16, - ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) + ) (*CoordinatorRandomWordsRequested, error) RequestRandomWordsWithForceFulfill( + coordinator Coordinator, keyHash [32]byte, requestConfirmations uint16, callbackGasLimit uint32, @@ -227,7 +243,7 @@ type VRFv2LoadTestConsumer interface { requestCount uint16, subTopUpAmount *big.Int, linkAddress common.Address, - ) (*types.Transaction, error) + ) (*CoordinatorRandomWordsRequested, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_load_test_with_metrics.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) @@ -237,7 +253,7 @@ type VRFv2LoadTestConsumer interface { type VRFv2WrapperLoadTestConsumer interface { Address() string Fund(ethAmount *big.Float) error - RequestRandomness(coordinator VRFCoordinatorV2, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) + RequestRandomness(coordinator Coordinator, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*CoordinatorRandomWordsRequested, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetWrapper(ctx context.Context) (common.Address, error) @@ -246,7 +262,15 @@ type VRFv2WrapperLoadTestConsumer interface { type VRFv2PlusLoadTestConsumer interface { Address() string - RequestRandomness(keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, nativePayment bool, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomness( + coordinator Coordinator, + keyHash [32]byte, subID *big.Int, + requestConfirmations uint16, + callbackGasLimit uint32, + nativePayment bool, + numWords uint32, + requestCount uint16, + ) (*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) @@ -257,8 +281,20 @@ type VRFv2PlusLoadTestConsumer interface { type VRFv2PlusWrapperLoadTestConsumer interface { Address() string Fund(ethAmount *big.Float) error - RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) - RequestRandomnessNative(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomness( + coordinator Coordinator, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + ) (*CoordinatorRandomWordsRequested, error) + RequestRandomnessNative( + coordinator Coordinator, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + ) (*CoordinatorRandomWordsRequested, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetWrapper(ctx context.Context) (common.Address, error) diff --git a/integration-tests/contracts/ethereum_vrf_common.go b/integration-tests/contracts/ethereum_vrf_common.go new file mode 100644 index 00000000000..d7eafe42a07 --- /dev/null +++ b/integration-tests/contracts/ethereum_vrf_common.go @@ -0,0 +1,124 @@ +package contracts + +import ( + "fmt" + "math/big" + "time" + + "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" +) + +type Coordinator interface { + ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) + Address() string + WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) + WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) +} + +type Subscription struct { + Balance *big.Int + NativeBalance *big.Int + ReqCount uint64 + SubOwner common.Address + Consumers []common.Address +} + +type CoordinatorConfigSet struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 + FallbackWeiPerUnitLink *big.Int + FulfillmentFlatFeeNativePPM uint32 + FulfillmentFlatFeeLinkDiscountPPM uint32 + NativePremiumPercentage uint8 + LinkPremiumPercentage uint8 + FeeConfig VRFCoordinatorV2FeeConfig + Raw types.Log +} + +type VRFCoordinatorV2FeeConfig struct { + FulfillmentFlatFeeLinkPPMTier1 uint32 + FulfillmentFlatFeeLinkPPMTier2 uint32 + FulfillmentFlatFeeLinkPPMTier3 uint32 + FulfillmentFlatFeeLinkPPMTier4 uint32 + FulfillmentFlatFeeLinkPPMTier5 uint32 + ReqsForTier2 *big.Int + ReqsForTier3 *big.Int + ReqsForTier4 *big.Int + ReqsForTier5 *big.Int +} + +type RandomWordsFulfilledEventFilter struct { + RequestIds []*big.Int + SubIDs []*big.Int + Timeout time.Duration +} + +type CoordinatorRandomWordsFulfilled struct { + RequestId *big.Int + OutputSeed *big.Int + SubId string + Payment *big.Int + NativePayment bool + Success bool + OnlyPremium bool + Raw types.Log +} + +type CoordinatorRandomWordsRequested struct { + KeyHash [32]byte + RequestId *big.Int + PreSeed *big.Int + SubId string + MinimumRequestConfirmations uint16 + CallbackGasLimit uint32 + NumWords uint32 + ExtraArgs []byte + Sender common.Address + Raw types.Log +} + +func parseRequestRandomnessLogs(coordinator Coordinator, logs []*types.Log) (*CoordinatorRandomWordsRequested, error) { + var randomWordsRequestedEvent *CoordinatorRandomWordsRequested + var err error + for _, eventLog := range logs { + for _, topic := range eventLog.Topics { + if topic.Cmp(vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested{}.Topic()) == 0 { + randomWordsRequestedEvent, err = coordinator.ParseRandomWordsRequested(*eventLog) + if err != nil { + return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) + } + } + if topic.Cmp(vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested{}.Topic()) == 0 { + randomWordsRequestedEvent, err = coordinator.ParseRandomWordsRequested(*eventLog) + if err != nil { + return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) + } + } + } + } + return randomWordsRequestedEvent, 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_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index ed99fb91109..c5116856d48 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "math/big" + "strconv" "time" "github.com/ethereum/go-ethereum" @@ -248,16 +249,22 @@ func (v *EthereumVRFCoordinatorV2) HashOfKey(ctx context.Context, pubKey [2]*big return hash, nil } -func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID uint64) (vrf_coordinator_v2.GetSubscription, error) { +func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID uint64) (Subscription, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, } subscription, err := v.coordinator.GetSubscription(opts, subID) if err != nil { - return vrf_coordinator_v2.GetSubscription{}, err + return Subscription{}, err } - return subscription, nil + return Subscription{ + Balance: subscription.Balance, + NativeBalance: nil, + SubOwner: subscription.Owner, + Consumers: subscription.Consumers, + ReqCount: subscription.ReqCount, + }, nil } func (v *EthereumVRFCoordinatorV2) GetOwner(ctx context.Context) (common.Address, error) { @@ -448,8 +455,24 @@ func (v *EthereumVRFCoordinatorV2) ParseSubscriptionCanceled(log types.Log) (*vr return v.coordinator.ParseSubscriptionCanceled(log) } -func (v *EthereumVRFCoordinatorV2) ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { - return v.coordinator.ParseRandomWordsRequested(log) +func (v *EthereumVRFCoordinatorV2) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) { + requested, err := v.coordinator.ParseRandomWordsRequested(log) + if err != nil { + return nil, fmt.Errorf("failed to parse RandomWordsRequested event: %w", err) + } + + return &CoordinatorRandomWordsRequested{ + KeyHash: requested.KeyHash, + RequestId: requested.RequestId, + PreSeed: requested.PreSeed, + SubId: strconv.FormatUint(requested.SubId, 10), + MinimumRequestConfirmations: requested.MinimumRequestConfirmations, + CallbackGasLimit: requested.CallbackGasLimit, + NumWords: requested.NumWords, + Sender: requested.Sender, + ExtraArgs: nil, + Raw: requested.Raw, + }, nil } func (v *EthereumVRFCoordinatorV2) ParseLog(log types.Log) (generated.AbigenLog, error) { @@ -492,9 +515,9 @@ func (v *EthereumVRFCoordinatorV2) FindSubscriptionID(subID uint64) (uint64, err return subscriptionIterator.Event.SubId, nil } -func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { +func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled) - subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID) + subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, filter.RequestIds) if err != nil { return nil, err } @@ -504,10 +527,16 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(requestID [] select { case err := <-subscription.Err(): return nil, err - case <-time.After(timeout): + case <-time.After(filter.Timeout): return nil, fmt.Errorf("timeout waiting for RandomWordsFulfilled event") case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: - return randomWordsFulfilledEvent, nil + return &CoordinatorRandomWordsFulfilled{ + RequestId: randomWordsFulfilledEvent.RequestId, + OutputSeed: randomWordsFulfilledEvent.OutputSeed, + Payment: randomWordsFulfilledEvent.Payment, + Success: randomWordsFulfilledEvent.Success, + Raw: randomWordsFulfilledEvent.Raw, + }, nil } } } @@ -632,7 +661,7 @@ func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerRemoved(subID []ui } } -func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) { +func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) { eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) subscription, err := v.coordinator.WatchConfigSet(nil, eventsChannel) if err != nil { @@ -647,7 +676,24 @@ func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) case <-time.After(timeout): return nil, fmt.Errorf("timeout waiting for ConfigSet event") case event := <-eventsChannel: - return event, nil + return &CoordinatorConfigSet{ + MinimumRequestConfirmations: event.MinimumRequestConfirmations, + MaxGasLimit: event.MaxGasLimit, + StalenessSeconds: event.StalenessSeconds, + GasAfterPaymentCalculation: event.GasAfterPaymentCalculation, + FallbackWeiPerUnitLink: event.FallbackWeiPerUnitLink, + FeeConfig: VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: event.FeeConfig.FulfillmentFlatFeeLinkPPMTier1, + FulfillmentFlatFeeLinkPPMTier2: event.FeeConfig.FulfillmentFlatFeeLinkPPMTier2, + FulfillmentFlatFeeLinkPPMTier3: event.FeeConfig.FulfillmentFlatFeeLinkPPMTier3, + FulfillmentFlatFeeLinkPPMTier4: event.FeeConfig.FulfillmentFlatFeeLinkPPMTier4, + FulfillmentFlatFeeLinkPPMTier5: event.FeeConfig.FulfillmentFlatFeeLinkPPMTier5, + ReqsForTier2: event.FeeConfig.ReqsForTier2, + ReqsForTier3: event.FeeConfig.ReqsForTier3, + ReqsForTier4: event.FeeConfig.ReqsForTier4, + ReqsForTier5: event.FeeConfig.ReqsForTier5, + }, + }, nil } } } @@ -794,14 +840,14 @@ func (v *EthereumVRFv2LoadTestConsumer) Address() string { } func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( - coordinator VRFCoordinatorV2, + coordinator Coordinator, keyHash [32]byte, subID uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { +) (*CoordinatorRandomWordsRequested, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return nil, err @@ -810,23 +856,15 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( if err != nil { return nil, fmt.Errorf("RequestRandomWords failed, err: %w", err) } - err = v.client.ProcessTransaction(tx) - if err != nil { - return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) - } - err = v.client.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) - } - receipt, err := v.client.GetTxReceipt(tx.Hash()) + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) if err != nil { - return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) + return nil, err } - randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, receipt.Logs) - return randomWordsRequestedEvent, err + return randomWordsRequestedEvent, nil } func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( + coordinator Coordinator, keyHash [32]byte, requestConfirmations uint16, callbackGasLimit uint32, @@ -834,7 +872,7 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( requestCount uint16, subTopUpAmount *big.Int, linkAddress common.Address, -) (*types.Transaction, error) { +) (*CoordinatorRandomWordsRequested, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return nil, err @@ -849,10 +887,14 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( subTopUpAmount, linkAddress, ) + if err != nil { + return nil, fmt.Errorf("RequestRandomWords failed, err: %w", err) + } + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) if err != nil { return nil, err } - return tx, v.client.ProcessTransaction(tx) + return randomWordsRequestedEvent, nil } func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) { @@ -990,7 +1032,7 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(ethAmount *big.Float) error return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) } -func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(coordinator VRFCoordinatorV2, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { +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 @@ -999,23 +1041,11 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(coordinator VRF if err != nil { return nil, err } - err = v.client.ProcessTransaction(tx) + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) if err != nil { return nil, err } - err = v.client.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) - } - receipt, err := v.client.GetTxReceipt(tx.Hash()) - if err != nil { - return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) - } - randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, receipt.Logs) - if err != nil { - return nil, err - } - return randomWordsRequestedEvent, err + return randomWordsRequestedEvent, nil } func (v *EthereumVRFV2WrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) { @@ -1199,19 +1229,3 @@ func (v *EthereumVRFMockETHLINKFeed) SetBlockTimestampDeduction(blockTimestampDe } return v.client.ProcessTransaction(tx) } - -func parseRequestRandomnessLogs(coordinator VRFCoordinatorV2, logs []*types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { - var randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested - var err error - for _, eventLog := range logs { - for _, topic := range eventLog.Topics { - if topic.Cmp(vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested{}.Topic()) == 0 { - randomWordsRequestedEvent, err = coordinator.ParseRandomWordsRequested(*eventLog) - if err != nil { - return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) - } - } - } - } - return randomWordsRequestedEvent, nil -} diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 432f700fa04..6d4bfcea647 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -57,7 +57,8 @@ func (v *EthereumVRFV2PlusWrapper) Address() string { } func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, - coordinatorGasOverhead uint32, + coordinatorGasOverheadNative uint32, + coordinatorGasOverheadLink uint32, coordinatorGasOverheadPerWord uint16, wrapperNativePremiumPercentage uint8, wrapperLinkPremiumPercentage uint8, @@ -75,7 +76,8 @@ func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, tx, err := v.wrapper.SetConfig( opts, wrapperGasOverhead, - coordinatorGasOverhead, + coordinatorGasOverheadNative, + coordinatorGasOverheadLink, coordinatorGasOverheadPerWord, wrapperNativePremiumPercentage, wrapperLinkPremiumPercentage, @@ -165,16 +167,42 @@ func (v *EthereumVRFCoordinatorV2_5) PendingRequestsExist(ctx context.Context, s return pendingRequestExists, nil } -func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) { +func (v *EthereumVRFCoordinatorV2_5) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) { + randomWordsRequested, err := v.coordinator.ParseRandomWordsRequested(log) + if err != nil { + return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) + } + coordinatorRandomWordsRequested := &CoordinatorRandomWordsRequested{ + KeyHash: randomWordsRequested.KeyHash, + RequestId: randomWordsRequested.RequestId, + PreSeed: randomWordsRequested.PreSeed, + SubId: randomWordsRequested.SubId.String(), + MinimumRequestConfirmations: randomWordsRequested.MinimumRequestConfirmations, + CallbackGasLimit: randomWordsRequested.CallbackGasLimit, + NumWords: randomWordsRequested.NumWords, + ExtraArgs: randomWordsRequested.ExtraArgs, + Sender: randomWordsRequested.Sender, + Raw: randomWordsRequested.Raw, + } + return coordinatorRandomWordsRequested, nil +} + +func (v *EthereumVRFCoordinatorV2_5) GetSubscription(ctx context.Context, subID *big.Int) (Subscription, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, } subscription, err := v.coordinator.GetSubscription(opts, subID) if err != nil { - return vrf_coordinator_v2_5.GetSubscription{}, err + return Subscription{}, err } - return subscription, nil + return Subscription{ + Balance: subscription.Balance, + NativeBalance: subscription.NativeBalance, + SubOwner: subscription.SubOwner, + Consumers: subscription.Consumers, + ReqCount: subscription.ReqCount, + }, nil } func (v *EthereumVRFCoordinatorV2_5) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) { @@ -455,9 +483,9 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCanceledEvent(subID *big } } -func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { +func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) - subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID, subID) + subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, filter.RequestIds, filter.SubIDs) if err != nil { return nil, err } @@ -467,30 +495,48 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(subID []*b select { case err := <-subscription.Err(): return nil, err - case <-time.After(timeout): + case <-time.After(filter.Timeout): return nil, fmt.Errorf("timeout waiting for RandomWordsFulfilled event") case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: - return randomWordsFulfilledEvent, nil + return &CoordinatorRandomWordsFulfilled{ + RequestId: randomWordsFulfilledEvent.RequestId, + OutputSeed: randomWordsFulfilledEvent.OutputSeed, + SubId: randomWordsFulfilledEvent.SubId.String(), + Payment: randomWordsFulfilledEvent.Payment, + NativePayment: randomWordsFulfilledEvent.NativePayment, + Success: randomWordsFulfilledEvent.Success, + OnlyPremium: randomWordsFulfilledEvent.OnlyPremium, + Raw: randomWordsFulfilledEvent.Raw, + }, nil } } } -func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) { - randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested) - subscription, err := v.coordinator.WatchRandomWordsRequested(nil, randomWordsFulfilledEventsChannel, keyHash, subID, sender) +func (v *EthereumVRFCoordinatorV2_5) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) { + eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25ConfigSet) + subscription, err := v.coordinator.WatchConfigSet(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 RandomWordsRequested event") - case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: - return randomWordsFulfilledEvent, nil + return nil, fmt.Errorf("timeout waiting for ConfigSet event") + case event := <-eventsChannel: + return &CoordinatorConfigSet{ + MinimumRequestConfirmations: event.MinimumRequestConfirmations, + MaxGasLimit: event.MaxGasLimit, + StalenessSeconds: event.StalenessSeconds, + GasAfterPaymentCalculation: event.GasAfterPaymentCalculation, + FallbackWeiPerUnitLink: event.FallbackWeiPerUnitLink, + FulfillmentFlatFeeNativePPM: event.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkDiscountPPM: event.FulfillmentFlatFeeLinkDiscountPPM, + NativePremiumPercentage: event.NativePremiumPercentage, + LinkPremiumPercentage: event.LinkPremiumPercentage, + }, nil } } } @@ -518,7 +564,15 @@ func (v *EthereumVRFCoordinatorV2_5) WaitForMigrationCompletedEvent(timeout time func (v *EthereumVRFv2PlusLoadTestConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness(keyHash [32]byte, subID *big.Int, requestConfirmations uint16, callbackGasLimit uint32, nativePayment bool, numWords uint32, requestCount uint16) (*types.Transaction, error) { +func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness( + coordinator Coordinator, + keyHash [32]byte, subID *big.Int, + requestConfirmations uint16, + callbackGasLimit uint32, + nativePayment bool, + numWords uint32, + requestCount uint16, +) (*CoordinatorRandomWordsRequested, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return nil, err @@ -527,8 +581,11 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness(keyHash [32]byte, if err != nil { return nil, err } - - return tx, v.client.ProcessTransaction(tx) + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + if err != nil { + return nil, err + } + return randomWordsRequestedEvent, nil } func (v *EthereumVRFv2PlusLoadTestConsumer) ResetMetrics() error { @@ -734,7 +791,8 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetConfig( fulfillmentFlatFeeNativePPM uint32, fulfillmentFlatFeeLinkDiscountPPM uint32, nativePremiumPercentage uint8, - linkPremiumPercentage uint8) error { + linkPremiumPercentage uint8, +) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -775,12 +833,13 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetLINKAndLINKNativeFeed(l 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) + tx, err := v.coordinator.RegisterProvingKey(opts, publicProvingKey, gasLaneMaxGas) if err != nil { return err } @@ -895,9 +954,9 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) FindSubscriptionID() (*big return subscriptionIterator.Event.SubId, nil } -func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { +func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForRandomWordsFulfilledEvent(filter RandomWordsFulfilledEventFilter) (*CoordinatorRandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled) - subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID, subID) + subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, filter.RequestIds, filter.SubIDs) if err != nil { return nil, err } @@ -907,10 +966,19 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForRandomWordsFulfille select { case err := <-subscription.Err(): return nil, err - case <-time.After(timeout): + case <-time.After(filter.Timeout): return nil, fmt.Errorf("timeout waiting for RandomWordsFulfilled event") case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: - return randomWordsFulfilledEvent, nil + return &CoordinatorRandomWordsFulfilled{ + RequestId: randomWordsFulfilledEvent.RequestId, + OutputSeed: randomWordsFulfilledEvent.OutputSeed, + SubId: randomWordsFulfilledEvent.SubId.String(), + Payment: randomWordsFulfilledEvent.Payment, + NativePayment: randomWordsFulfilledEvent.NativePayment, + Success: randomWordsFulfilledEvent.Success, + OnlyPremium: randomWordsFulfilledEvent.OnlyPremium, + Raw: randomWordsFulfilledEvent.Raw, + }, nil } } } @@ -919,7 +987,7 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForMigrationCompletedE eventsChannel := make(chan *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMigrationCompleted) subscription, err := v.coordinator.WatchMigrationCompleted(nil, eventsChannel) if err != nil { - return nil, err + return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) } defer subscription.Unsubscribe() @@ -935,22 +1003,51 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForMigrationCompletedE } } -func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, error) { - eventsChannel := make(chan *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested) - subscription, err := v.coordinator.WatchRandomWordsRequested(nil, eventsChannel, keyHash, subID, sender) +func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) ParseRandomWordsRequested(log types.Log) (*CoordinatorRandomWordsRequested, error) { + randomWordsRequested, err := v.coordinator.ParseRandomWordsRequested(log) if err != nil { return nil, err } - defer subscription.Unsubscribe() + coordinatorRandomWordsRequested := &CoordinatorRandomWordsRequested{ + KeyHash: randomWordsRequested.KeyHash, + RequestId: randomWordsRequested.RequestId, + PreSeed: randomWordsRequested.PreSeed, + SubId: randomWordsRequested.SubId.String(), + MinimumRequestConfirmations: randomWordsRequested.MinimumRequestConfirmations, + CallbackGasLimit: randomWordsRequested.CallbackGasLimit, + NumWords: randomWordsRequested.NumWords, + ExtraArgs: randomWordsRequested.ExtraArgs, + Sender: randomWordsRequested.Sender, + Raw: randomWordsRequested.Raw, + } + return coordinatorRandomWordsRequested, nil +} +func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error) { + eventsChannel := make(chan *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionConfigSet) + subscription, err := v.coordinator.WatchConfigSet(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 RandomWordsRequested event") - case randomWordsRequestedEvent := <-eventsChannel: - return randomWordsRequestedEvent, nil + return nil, fmt.Errorf("timeout waiting for ConfigSet event") + case event := <-eventsChannel: + return &CoordinatorConfigSet{ + MinimumRequestConfirmations: event.MinimumRequestConfirmations, + MaxGasLimit: event.MaxGasLimit, + StalenessSeconds: event.StalenessSeconds, + GasAfterPaymentCalculation: event.GasAfterPaymentCalculation, + FallbackWeiPerUnitLink: event.FallbackWeiPerUnitLink, + FulfillmentFlatFeeNativePPM: event.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkDiscountPPM: event.FulfillmentFlatFeeLinkDiscountPPM, + NativePremiumPercentage: event.NativePremiumPercentage, + LinkPremiumPercentage: event.LinkPremiumPercentage, + }, nil } } } @@ -1020,7 +1117,13 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Fund(ethAmount *big.Float) er return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) } -func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) { +func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) 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 @@ -1029,11 +1132,20 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomness(requestConf if err != nil { return nil, err } - - return tx, v.client.ProcessTransaction(tx) + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + if err != nil { + return nil, err + } + return randomWordsRequestedEvent, nil } -func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomnessNative(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) { +func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomnessNative( + 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 @@ -1042,8 +1154,11 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) RequestRandomnessNative(reque if err != nil { return nil, err } - - return tx, v.client.ProcessTransaction(tx) + randomWordsRequestedEvent, err := RetrieveRequestRandomnessLogs(coordinator, v.client, tx) + if err != nil { + return nil, err + } + return randomWordsRequestedEvent, nil } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, error) { diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 09da97b40f3..7eee9231b17 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -339,6 +339,14 @@ func (n *ClNode) containerStartOrRestart(restartDb bool) error { return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } + // retries can change the container name which affects urls used later + // so update to use the name that actually started + n.ContainerName, err = container.Name(context.Background()) + if err != nil { + return err + } + n.ContainerName = strings.Replace(n.ContainerName, "/", "", -1) + clEndpoint, err := test_env.GetEndpoint(testcontext.Get(n.t), container, "http") if err != nil { return err diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index cbcb943e695..d54f51eeea1 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -34,6 +34,7 @@ type CLClusterTestEnv struct { Cfg *TestEnvConfig DockerNetwork *tc.DockerNetwork LogStream *logstream.LogStream + TestConfig core_testconfig.GlobalTestConfig /* components */ ClCluster *ClCluster @@ -201,7 +202,7 @@ func (te *CLClusterTestEnv) Terminate() error { func (te *CLClusterTestEnv) Cleanup() error { te.l.Info().Msg("Cleaning up test environment") - runIdErr := runid.RemoveLocalRunId() + runIdErr := runid.RemoveLocalRunId(te.TestConfig.GetLoggingConfig().RunId) if runIdErr != nil { te.l.Warn().Msgf("Failed to remove .run.id file due to: %s (not a big deal, you can still remove it manually)", runIdErr.Error()) } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index e057df03806..b9406bf16aa 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -224,6 +224,8 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } + b.te.TestConfig = b.testConfig + var err error if b.t != nil { b.te.WithTestInstance(b.t) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b3f0f7a90c6..e3afe782e95 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,14 +22,15 @@ require ( github.com/rs/zerolog v1.30.0 github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 + 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.20240415164156-8872a8f311cb - github.com/smartcontractkit/chainlink-testing-framework v1.28.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 + github.com/smartcontractkit/chainlink-testing-framework v1.28.3 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-20240326191951-2bbe9382d052 - github.com/smartcontractkit/seth v0.1.5 + github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/seth v0.1.6 github.com/smartcontractkit/wasp v0.4.5 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 @@ -94,7 +95,6 @@ require ( github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -176,8 +176,8 @@ require ( github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gagliardetto/binary v0.7.1 // indirect - github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect + github.com/gagliardetto/binary v0.7.7 // indirect + github.com/gagliardetto/solana-go v1.8.4 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect @@ -368,23 +368,23 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday v1.6.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.7.2 // indirect + github.com/smartcontractkit/wsrpc v0.8.1 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/afero v1.9.5 // indirect @@ -393,6 +393,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.15.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect + github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/supranational/blst v0.3.11 // indirect @@ -425,7 +426,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.etcd.io/etcd/client/v3 v3.5.7 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect + go.mongodb.org/mongo-driver v1.15.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect go.opentelemetry.io/collector/semconv v0.87.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 957e3988143..5a8b091ebcc 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -216,8 +216,6 @@ github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3s github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= @@ -529,13 +527,12 @@ github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADi github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= -github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI= -github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= +github.com/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY= +github.com/gagliardetto/binary v0.7.7/go.mod h1:mUuay5LL8wFVnIlecHakSZMvcdqfs+CsotR5n77kyjM= github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 h1:q2IztKyRQUxJ6abXRsawaBtvDFvM+szj4jDqV4od1gs= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY= +github.com/gagliardetto/solana-go v1.8.4 h1:vmD/JmTlonyXGy39bAo0inMhmbdAwV7rXZtLDMZeodE= +github.com/gagliardetto/solana-go v1.8.4/go.mod h1:i+7aAyNDTHG0jK8GZIBSI4OVvDqkt2Qx+LklYclRNG8= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= @@ -826,7 +823,6 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1521,38 +1517,38 @@ 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.20240415164156-8872a8f311cb h1:yLDt5cQWRwcFM5VEdSTbc3vDrYrxYqBjSvyTMU/o8s4= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240415164156-8872a8f311cb/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 h1:elDIBChe7ByPNvCyrSjMLTPKrgY+sKgzzlWe2p3wokY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9/go.mod h1:GTDBbovHUSAUk+fuGIySF2A/whhdtHGaWmU61BoERks= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 h1:MvaNzuaQh1vX4CAYLM8qFd99cf0ZF1JNwtDZtLU7WvU= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92/go.mod h1:uATrrJ8IsuBkOBJ46USuf73gz9gZy5k5bzGE5/ji/rc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab h1:Ct1oUlyn03HDUVdFHJqtRGRUujMqdoMzvf/Cjhe30Ag= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab/go.mod h1:RPUY7r8GxgzXxS1ijtU1P/fpJomOXztXgUbEziNmbCA= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 h1:jc4ab5QrKZfkICyxJysCt7mSExuSPbePjgZsnJR3nRQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58/go.mod h1:oV5gIuSKrPEcjQ6uB6smBsm5kXHxyydVLNyAs4V9CoQ= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= -github.com/smartcontractkit/chainlink-testing-framework v1.28.2 h1:H4/RW9J3EmHi4uJUxREJHkxxBbKRRk/eO3YhuR9a9zI= -github.com/smartcontractkit/chainlink-testing-framework v1.28.2/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.3 h1:rZ622PUSE9jJvI2g1SNNcMJedXyMzq9XJ8SbV2j9TvA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.3/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= -github.com/smartcontractkit/seth v0.1.5 h1:tobdA3uzRHubN/ytE6bSq1dtvmaXjKdaHEGW5Re9I1U= -github.com/smartcontractkit/seth v0.1.5/go.mod h1:2TMOZQ8WTAw7rR1YBbXpnad6VmT/+xDd/nXLmB7Eero= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/seth v0.1.6 h1:exU96KiKM/gxvp7OR8KkOXnTgbtFNepdhMBvyobFKCw= +github.com/smartcontractkit/seth v0.1.6/go.mod h1:2TMOZQ8WTAw7rR1YBbXpnad6VmT/+xDd/nXLmB7Eero= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wasp v0.4.5 h1:pgiXwBci2m15eo33AzspzhpNG/gxg+8QGxl+I5LpfsQ= github.com/smartcontractkit/wasp v0.4.5/go.mod h1:eVhBVLbVv0qORUlN7aR5C4aTN/lTYO3KnN1erO4ROOI= -github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= -github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= +github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= +github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1589,6 +1585,8 @@ github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jH github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 h1:ZqpS7rAhhKD7S7DnrpEdrnW1/gZcv82ytpMviovkli4= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1693,10 +1691,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -1748,8 +1744,9 @@ go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/ go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1817,7 +1814,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= @@ -1847,11 +1844,11 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -1951,7 +1948,6 @@ golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2068,7 +2064,6 @@ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2184,7 +2179,6 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index cbde975afcc..95870bad6a2 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,12 +16,12 @@ 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.20240415164156-8872a8f311cb - github.com/smartcontractkit/chainlink-testing-framework v1.28.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 + github.com/smartcontractkit/chainlink-testing-framework v1.28.3 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-20240326191951-2bbe9382d052 - github.com/smartcontractkit/seth v0.1.5 + github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/seth v0.1.6 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.4.6 github.com/stretchr/testify v1.9.0 @@ -72,7 +72,6 @@ require ( github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/benbjohnson/clock v1.3.5 // indirect @@ -154,8 +153,8 @@ require ( github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gagliardetto/binary v0.7.1 // indirect - github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect + github.com/gagliardetto/binary v0.7.7 // indirect + github.com/gagliardetto/solana-go v1.8.4 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect @@ -355,6 +354,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday v1.6.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect @@ -366,15 +366,15 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea // indirect github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.7.2 // indirect + github.com/smartcontractkit/wsrpc v0.8.1 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/afero v1.9.5 // indirect @@ -384,6 +384,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.15.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect + github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/supranational/blst v0.3.11 // indirect @@ -420,7 +421,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.etcd.io/etcd/client/v3 v3.5.7 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect + go.mongodb.org/mongo-driver v1.15.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect go.opentelemetry.io/collector/semconv v0.87.0 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 2ae24681388..051fdf9cd6e 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -216,8 +216,6 @@ github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3s github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI= github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4= github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= @@ -519,13 +517,12 @@ github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADi github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= -github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI= -github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= +github.com/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY= +github.com/gagliardetto/binary v0.7.7/go.mod h1:mUuay5LL8wFVnIlecHakSZMvcdqfs+CsotR5n77kyjM= github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 h1:q2IztKyRQUxJ6abXRsawaBtvDFvM+szj4jDqV4od1gs= -github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY= +github.com/gagliardetto/solana-go v1.8.4 h1:vmD/JmTlonyXGy39bAo0inMhmbdAwV7rXZtLDMZeodE= +github.com/gagliardetto/solana-go v1.8.4/go.mod h1:i+7aAyNDTHG0jK8GZIBSI4OVvDqkt2Qx+LklYclRNG8= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= @@ -817,7 +814,6 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1504,20 +1500,20 @@ 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.20240415164156-8872a8f311cb h1:yLDt5cQWRwcFM5VEdSTbc3vDrYrxYqBjSvyTMU/o8s4= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240415164156-8872a8f311cb/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9 h1:elDIBChe7ByPNvCyrSjMLTPKrgY+sKgzzlWe2p3wokY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240419205832-845fa69af8d9/go.mod h1:GTDBbovHUSAUk+fuGIySF2A/whhdtHGaWmU61BoERks= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92 h1:MvaNzuaQh1vX4CAYLM8qFd99cf0ZF1JNwtDZtLU7WvU= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240419131812-73d148593d92/go.mod h1:uATrrJ8IsuBkOBJ46USuf73gz9gZy5k5bzGE5/ji/rc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab h1:Ct1oUlyn03HDUVdFHJqtRGRUujMqdoMzvf/Cjhe30Ag= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab/go.mod h1:RPUY7r8GxgzXxS1ijtU1P/fpJomOXztXgUbEziNmbCA= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58 h1:jc4ab5QrKZfkICyxJysCt7mSExuSPbePjgZsnJR3nRQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240422172640-59d47c73ba58/go.mod h1:oV5gIuSKrPEcjQ6uB6smBsm5kXHxyydVLNyAs4V9CoQ= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= -github.com/smartcontractkit/chainlink-testing-framework v1.28.2 h1:H4/RW9J3EmHi4uJUxREJHkxxBbKRRk/eO3YhuR9a9zI= -github.com/smartcontractkit/chainlink-testing-framework v1.28.2/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.3 h1:rZ622PUSE9jJvI2g1SNNcMJedXyMzq9XJ8SbV2j9TvA= +github.com/smartcontractkit/chainlink-testing-framework v1.28.3/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea h1:ZdLmNAfKRjH8AYUvjiiDGUgiWQfq/7iNpxyTkvjx/ko= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea/go.mod h1:gCKC9w6XpNk6jm+XIk2psrkkfxhi421N9NSiFceXW88= github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= @@ -1526,18 +1522,18 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= -github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= -github.com/smartcontractkit/seth v0.1.5 h1:tobdA3uzRHubN/ytE6bSq1dtvmaXjKdaHEGW5Re9I1U= -github.com/smartcontractkit/seth v0.1.5/go.mod h1:2TMOZQ8WTAw7rR1YBbXpnad6VmT/+xDd/nXLmB7Eero= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= +github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/seth v0.1.6 h1:exU96KiKM/gxvp7OR8KkOXnTgbtFNepdhMBvyobFKCw= +github.com/smartcontractkit/seth v0.1.6/go.mod h1:2TMOZQ8WTAw7rR1YBbXpnad6VmT/+xDd/nXLmB7Eero= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wasp v0.4.6 h1:s6J8HgpxMHORl19nCpZPxc5jaVUQv8EXB6QjTuLXXnw= github.com/smartcontractkit/wasp v0.4.6/go.mod h1:+ViWdUf1ap6powiEiwPskpZfH/Q1sG29YoVav7zGOIo= -github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= -github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= +github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= +github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1574,6 +1570,8 @@ github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jH github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 h1:ZqpS7rAhhKD7S7DnrpEdrnW1/gZcv82ytpMviovkli4= +github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1678,10 +1676,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -1733,8 +1729,9 @@ go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/ go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1802,7 +1799,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= @@ -1832,11 +1829,11 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -1937,7 +1934,6 @@ golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2053,7 +2049,6 @@ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2171,7 +2166,6 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 61951ba700f..e63828a7d93 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -13,7 +13,7 @@ sudo kubefwd svc -n cl-cluster Change environment connection configuration [here](../../../charts/chainlink-cluster/connect.toml) -If you haven't changed anything in [devspace.yaml](../../../charts/chainlink-cluster/devspace.yaml) then default connection configuration will work +If you haven't changed anything in [devspace.yaml](../../crib/devspace.yaml) then default connection configuration will work ## Usage diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 0edf35df8fa..e420d66ec8c 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -2,6 +2,7 @@ package loadvrfv2 import ( "math/big" + "strconv" "sync" "testing" "time" @@ -26,12 +27,6 @@ import ( ) var ( - testEnv *test_env.CLClusterTestEnv - vrfContracts *vrfcommon.VRFContracts - vrfKey *vrfcommon.VRFKeyData - subIDs []uint64 - eoaWalletAddress string - labels = map[string]string{ "branch": "vrfv2_healthcheck", "commit": "vrfv2_healthcheck", @@ -39,24 +34,30 @@ var ( ) func TestVRFV2Performance(t *testing.T) { + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) - testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) testConfig, err := tc.GetConfig(testType, tc.VRFv2) require.NoError(t, err) + cfgl := testConfig.Logging.Loki - testReporter := &testreporters.VRFV2TestReporter{} vrfv2Config := testConfig.VRFv2 + testReporter := &testreporters.VRFV2TestReporter{} - cfgl := testConfig.Logging.Loki lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { l.Error().Err(err).Msg(ErrLokiClient) return } - + chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID updatedLabels := UpdateLabels(labels, t) l.Info(). @@ -68,9 +69,6 @@ func TestVRFV2Performance(t *testing.T) { Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2Config.General.RandomnessRequestCountPerRequestDeviation). Bool("UseExistingEnv", *vrfv2Config.General.UseExistingEnv). Msg("Performance Test Configuration") - - chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID - cleanupFn := func() { teardown(t, vrfContracts.VRFV2Consumers[0], lc, updatedLabels, testReporter, testType, &testConfig) @@ -84,7 +82,7 @@ func TestVRFV2Performance(t *testing.T) { } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -108,7 +106,7 @@ func TestVRFV2Performance(t *testing.T) { require.NoError(t, err, "error getting EVM client") var consumers []contracts.VRFv2LoadTestConsumer - subIDs, consumers, err = vrfv2.SetupSubsAndConsumersForExistingEnv( + subIDs, consumers, err := vrfv2.SetupSubsAndConsumersForExistingEnv( testEnv, chainID, vrfContracts.CoordinatorV2, @@ -118,16 +116,17 @@ func TestVRFV2Performance(t *testing.T) { testConfig, l, ) - vrfContracts.VRFV2Consumers = consumers - - eoaWalletAddress = evmClient.GetDefaultWallet().Address() - - l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") + require.NoError(t, err, "error setting up new consumers and subs") for _, subID := range subIDs { subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information for subscription %d", subID) - vrfv2.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subID, 10), vrfContracts.CoordinatorV2) } + subIDsForCancellingAfterTest = subIDs + 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) { @@ -177,16 +176,21 @@ func TestVRFV2Performance(t *testing.T) { } func TestVRFV2BHSPerformance(t *testing.T) { + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) testConfig, err := tc.GetConfig(testType, tc.VRFv2) require.NoError(t, err) - - testReporter := &testreporters.VRFV2TestReporter{} vrfv2Config := testConfig.VRFv2 - + testReporter := &testreporters.VRFV2TestReporter{} cfgl := testConfig.Logging.Loki lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) lc, err := wasp.NewLokiClient(lokiConfig) @@ -222,7 +226,7 @@ func TestVRFV2BHSPerformance(t *testing.T) { } else { if *vrfv2Config.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) } } if !*vrfv2Config.General.UseExistingEnv { @@ -245,43 +249,29 @@ func TestVRFV2BHSPerformance(t *testing.T) { evmClient, err := testEnv.GetEVMClient(chainID) require.NoError(t, err, "error getting EVM client") - var consumers []contracts.VRFv2LoadTestConsumer - subIDs, consumers, err = vrfv2.SetupSubsAndConsumersForExistingEnv( - testEnv, - chainID, - vrfContracts.CoordinatorV2, - vrfContracts.LinkToken, - 1, - *vrfv2Config.General.NumberOfSubToCreate, - testConfig, - l, - ) - vrfContracts.VRFV2Consumers = consumers - - eoaWalletAddress = evmClient.GetDefaultWallet().Address() - - l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") - for _, subID := range subIDs { - subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information for subscription %d", subID) - vrfv2.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2) - } - + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("vrfv2 and bhs performance test", func(t *testing.T) { configCopy := testConfig.MustCopy().(tc.TestConfig) //Underfund Subscription configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) - consumers, subIDs, err = vrfv2.SetupNewConsumersAndSubs( + underfundedSubIDs, consumers, err := vrfv2.SetupSubsAndConsumersForExistingEnv( testEnv, chainID, vrfContracts.CoordinatorV2, - configCopy, vrfContracts.LinkToken, 1, - *configCopy.VRFv2.General.NumberOfSubToCreate, + *vrfv2Config.General.NumberOfSubToCreate, + configCopy, l, ) - require.NoError(t, err, "error setting up new consumers and subscriptions") + require.NoError(t, err, "error setting up new consumers and subs") + for _, subID := range underfundedSubIDs { + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information for subscription %d", subID) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subID, 10), vrfContracts.CoordinatorV2) + } + subIDsForCancellingAfterTest = underfundedSubIDs + l.Debug().Int("Number of Subs", len(underfundedSubIDs)).Msg("Subs involved in the test") vrfContracts.VRFV2Consumers = consumers require.Len(t, vrfContracts.VRFV2Consumers, 1, "only one consumer should be created for Load Test") err = vrfContracts.VRFV2Consumers[0].ResetMetrics() @@ -296,7 +286,7 @@ func TestVRFV2BHSPerformance(t *testing.T) { Gun: NewBHSTestGun( vrfContracts, vrfKey.KeyHash, - subIDs, + underfundedSubIDs, configCopy.VRFv2, l, ), @@ -322,8 +312,27 @@ func TestVRFV2BHSPerformance(t *testing.T) { _, err = actions.WaitForBlockNumberToBe(latestBlockNumber+uint64(256), evmClient, &wgBlockNumberTobe, configCopy.VRFv2.General.WaitFor256BlocksTimeout.Duration, t) wgBlockNumberTobe.Wait() require.NoError(t, err, "error waiting for block number to be") - err = vrfv2.FundSubscriptions(testEnv, chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDs) + + metrics, err := consumers[0].GetLoadTestMetrics(testcontext.Get(t)) + require.NoError(t, err) + require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0)), "Fulfilment count should be 0 since sub is underfunded. Check if the sub is actually funded") + + var subIDsString []uint64 + subIDsString = append(subIDsString, underfundedSubIDs...) + l.Info(). + Float64("SubscriptionRefundingAmountLink", *configCopy.VRFv2.General.SubscriptionRefundingAmountLink). + 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, + underfundedSubIDs, + ) require.NoError(t, err, "error funding subscriptions") + var wgAllRequestsFulfilled sync.WaitGroup wgAllRequestsFulfilled.Add(1) requestCount, fulfilmentCount, err := vrfcommon.WaitForRequestCountEqualToFulfilmentCount(testcontext.Get(t), vrfContracts.VRFV2Consumers[0], 2*time.Minute, &wgAllRequestsFulfilled) diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 8be30afd412..8a99392fa57 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -44,7 +44,7 @@ func (m *BHSTestGun) Call(_ *wasp.Generator) *wasp.Response { if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} } - _, err = vrfv2plus.RequestRandomnessAndWaitForRequestedEvent( + _, err = vrfv2plus.RequestRandomness( //the same consumer is used for all requests and in all subs m.contracts.VRFV2PlusConsumer[0], m.contracts.CoordinatorV2Plus, diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 1589123c77e..d461b4cde20 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -26,12 +26,6 @@ import ( ) var ( - testEnv *test_env.CLClusterTestEnv - vrfContracts *vrfcommon.VRFContracts - vrfKey *vrfcommon.VRFKeyData - subIDs []*big.Int - eoaWalletAddress string - labels = map[string]string{ "branch": "vrfv2Plus_healthcheck", "commit": "vrfv2Plus_healthcheck", @@ -39,8 +33,14 @@ var ( ) func TestVRFV2PlusPerformance(t *testing.T) { + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) - testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) @@ -56,8 +56,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Error().Err(err).Msg(ErrLokiClient) return } - - networkConfig := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID updatedLabels := UpdateLabels(labels, t) l.Info(). @@ -73,8 +72,8 @@ func TestVRFV2PlusPerformance(t *testing.T) { cleanupFn := func() { teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, testType, &testConfig) - evmClient, err := testEnv.GetEVMClient(networkConfig.ChainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") if evmClient.NetworkSimulated() { l.Info(). @@ -83,7 +82,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { } else { if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) } } if !*testConfig.VRFv2Plus.General.UseExistingEnv { @@ -98,16 +97,16 @@ func TestVRFV2PlusPerformance(t *testing.T) { NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, } - testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, networkConfig.ChainID, cleanupFn, newEnvConfig, l) + testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) require.NoError(t, err, "error setting up VRFV2Plus universe") - evmClient, err := testEnv.GetEVMClient(networkConfig.ChainID) + evmClient, err := testEnv.GetEVMClient(chainID) require.NoError(t, err, "Getting EVM client shouldn't fail") var consumers []contracts.VRFv2PlusLoadTestConsumer - subIDs, consumers, err = vrfv2plus.SetupSubsAndConsumersForExistingEnv( + subIDs, consumers, err := vrfv2plus.SetupSubsAndConsumersForExistingEnv( testEnv, - networkConfig.ChainID, + chainID, vrfContracts.CoordinatorV2Plus, vrfContracts.LinkToken, 1, @@ -115,19 +114,26 @@ func TestVRFV2PlusPerformance(t *testing.T) { testConfig, l, ) - vrfContracts.VRFV2PlusConsumer = consumers - - eoaWalletAddress = evmClient.GetDefaultWallet().Address() - - l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") + require.NoError(t, err, "error setting up new consumers and subs") for _, subID := range subIDs { subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) } + subIDsForCancellingAfterTest = subIDs + 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) { + require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") + consumer := vrfContracts.VRFV2PlusConsumer[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + MonitorLoadStats(testcontext.Get(t), lc, consumer, updatedLabels) + singleFeedConfig := &wasp.Config{ T: t, LoadType: wasp.RPS, @@ -144,11 +150,6 @@ func TestVRFV2PlusPerformance(t *testing.T) { LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), CallTimeout: 2 * time.Minute, } - require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") - consumer := vrfContracts.VRFV2PlusConsumer[0] - err = consumer.ResetMetrics() - require.NoError(t, err) - MonitorLoadStats(testcontext.Get(t), lc, consumer, updatedLabels) singleFeedConfig.Schedule = wasp.Plain( *vrfv2PlusConfig.Performance.RPS, @@ -174,17 +175,22 @@ func TestVRFV2PlusPerformance(t *testing.T) { } func TestVRFV2PlusBHSPerformance(t *testing.T) { + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) require.NoError(t, err) - cfgl := testConfig.Logging.Loki - vrfv2PlusConfig := testConfig.VRFv2Plus testReporter := &testreporters.VRFV2PlusTestReporter{} - + cfgl := testConfig.Logging.Loki lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { @@ -219,7 +225,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { } else { if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner - vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) } } if !*testConfig.VRFv2Plus.General.UseExistingEnv { @@ -240,30 +246,32 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { evmClient, err := testEnv.GetEVMClient(chainID) require.NoError(t, err, "error getting EVM client") - eoaWalletAddress = evmClient.GetDefaultWallet().Address() - - l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") - for _, subID := range subIDs { - subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) - } + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("vrfv2plus and bhs performance test", func(t *testing.T) { configCopy := testConfig.MustCopy().(tc.TestConfig) //Underfund Subscription configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) - consumers, underfundedSubIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) + + underfundedSubIDs, consumers, err := vrfv2plus.SetupSubsAndConsumersForExistingEnv( testEnv, chainID, vrfContracts.CoordinatorV2Plus, - configCopy, vrfContracts.LinkToken, 1, - *configCopy.VRFv2Plus.General.NumberOfSubToCreate, + *vrfv2PlusConfig.General.NumberOfSubToCreate, + configCopy, l, ) require.NoError(t, err, "error setting up new consumers and subs for Load Test") + for _, subID := range underfundedSubIDs { + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) + } + subIDsForCancellingAfterTest = underfundedSubIDs + l.Debug().Int("Number of Subs", len(underfundedSubIDs)).Msg("Subs involved in the test") vrfContracts.VRFV2PlusConsumer = consumers require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") consumer := vrfContracts.VRFV2PlusConsumer[0] @@ -306,6 +314,20 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { wgBlockNumberTobe.Wait() require.NoError(t, err, "error waiting for block number to be") + metrics, err := consumers[0].GetLoadTestMetrics(testcontext.Get(t)) + require.NoError(t, err) + require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0)), "Fulfilment count should be 0 since sub is underfunded. Check if the sub is actually funded") + + var subIDsString []string + for _, subID := range underfundedSubIDs { + subIDsString = append(subIDsString, subID.String()) + } + + l.Info(). + Float64("SubscriptionRefundingAmountNative", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative). + Float64("SubscriptionRefundingAmountLink", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink). + Strs("SubIDs", subIDsString). + Msg("Funding Subscriptions with Link and Native Tokens") err = vrfv2plus.FundSubscriptions( testEnv, chainID, @@ -313,7 +335,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2Plus, - subIDs, + underfundedSubIDs, ) require.NoError(t, err, "error funding subscriptions") diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index 3e7a82effd3..03029c9018b 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -2,7 +2,6 @@ "tests": [ { "name": "TestAutomationBasic", - "label": "ubuntu-latest", "nodes": 3, "run":[ {"name":"registry_2_0"}, @@ -12,7 +11,6 @@ }, { "name": "TestAutomationBasic", - "label": "ubuntu-latest", "nodes": 3, "run":[ {"name":"registry_2_1_with_mercury_v02"}, @@ -22,7 +20,6 @@ }, { "name": "TestAutomationBasic", - "label": "ubuntu-latest", "nodes": 3, "run":[ {"name":"registry_2_2_conditional"}, @@ -32,7 +29,6 @@ }, { "name": "TestAutomationBasic", - "label": "ubuntu-latest", "nodes": 2, "run":[ {"name":"registry_2_2_with_mercury_v03"}, @@ -41,47 +37,38 @@ }, { "name": "TestSetUpkeepTriggerConfig", - "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationAddFunds", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationPauseUnPause", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationRegisterUpkeep", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationPauseRegistry", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationKeeperNodesDown", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationPerformSimulation", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestAutomationCheckPerformGasLimit", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestUpdateCheckData", - "label": "ubuntu-latest", "nodes": 3 } ] diff --git a/integration-tests/smoke/evm_node_compatibility_test_list.json b/integration-tests/smoke/evm_node_compatibility_test_list.json index c14a2b54a3e..45b303a0a27 100644 --- a/integration-tests/smoke/evm_node_compatibility_test_list.json +++ b/integration-tests/smoke/evm_node_compatibility_test_list.json @@ -4,211 +4,181 @@ "product": "ocr", "name": "TestOCRBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "ocr", "name": "TestOCRBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "ocr", "name": "TestOCRBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "ocr", "name": "TestOCRBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "ocr", "name": "TestOCRBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" }, { "product": "ocr2", "name": "TestOCRv2Request", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "ocr2", "name": "TestOCRv2Request", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "ocr2", "name": "TestOCRv2Request", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "ocr2", "name": "TestOCRv2Request", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "ocr2", "name": "TestOCRv2Request", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" }, { "product": "vrf", "name": "TestVRFBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "vrf", "name": "TestVRFBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "vrf", "name": "TestVRFBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "vrf", "name": "TestVRFBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "vrf", "name": "TestVRFBasic", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" }, { "product": "vrfv2", "name": "TestVRFv2Basic/Request Randomness", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "vrfv2", "name": "TestVRFv2Basic/Request Randomness", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "vrfv2", "name": "TestVRFv2Basic/Request Randomness", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "vrfv2", "name": "TestVRFv2Basic/Request Randomness", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "vrfv2", "name": "TestVRFv2Basic/Request Randomness", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" }, { "product": "vrfv2plus", "name": "TestVRFv2Plus/Link Billing", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "vrfv2plus", "name": "TestVRFv2Plus/Link Billing", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "vrfv2plus", "name": "TestVRFv2Plus/Link Billing", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "vrfv2plus", "name": "TestVRFv2Plus/Link Billing", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "vrfv2plus", "name": "TestVRFv2Plus/Link Billing", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" }, { "product": "automation", "name": "TestSetUpkeepTriggerConfig", "eth_client": "geth", - "docker_image": "ethereum/client-go:latest_stable", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:latest_stable" }, { "product": "automation", "name": "TestSetUpkeepTriggerConfig", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.13.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.13.0" }, { "product": "automation", "name": "TestSetUpkeepTriggerConfig", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.12.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.12.0" }, { "product": "automation", "name": "TestSetUpkeepTriggerConfig", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.11.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.11.0" }, { "product": "automation", "name": "TestSetUpkeepTriggerConfig", "eth_client": "geth", - "docker_image": "ethereum/client-go:v1.10.0", - "label": "ubuntu-latest" + "docker_image": "ethereum/client-go:v1.10.0" } ] } \ No newline at end of file diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json index b2f4aa00659..b9ccaa0c008 100644 --- a/integration-tests/smoke/keeper_test.go_test_list.json +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -2,42 +2,34 @@ "tests": [ { "name": "TestKeeperBasicSmoke", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperBlockCountPerTurn", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperSimulation", - "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestKeeperCheckPerformGasLimit", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperRegisterUpkeep", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperAddFunds", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperRemove", - "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperPauseRegistry", - "label": "ubuntu-latest", "nodes": 2 }, { @@ -45,7 +37,6 @@ }, { "name": "TestKeeperNodeDown", - "label": "ubuntu-latest", "nodes": 3 }, { diff --git a/integration-tests/smoke/log_poller_test.go_test_list.json b/integration-tests/smoke/log_poller_test.go_test_list.json index 2159654e283..96939c5133b 100644 --- a/integration-tests/smoke/log_poller_test.go_test_list.json +++ b/integration-tests/smoke/log_poller_test.go_test_list.json @@ -1,44 +1,34 @@ { "tests": [ { - "name": "TestLogPollerFewFiltersFixedDepth", - "label": "ubuntu-latest" + "name": "TestLogPollerFewFiltersFixedDepth" }, { - "name": "TestLogPollerFewFiltersFinalityTag", - "label": "ubuntu-latest" + "name": "TestLogPollerFewFiltersFinalityTag" }, { - "name": "TestLogPollerWithChaosFixedDepth", - "label": "ubuntu-latest" + "name": "TestLogPollerWithChaosFixedDepth" }, { - "name": "TestLogPollerWithChaosFinalityTag", - "label": "ubuntu-latest" + "name": "TestLogPollerWithChaosFinalityTag" }, { - "name": "TestLogPollerWithChaosPostgresFinalityTag", - "label": "ubuntu-latest" + "name": "TestLogPollerWithChaosPostgresFinalityTag" }, { - "name": "TestLogPollerWithChaosPostgresFixedDepth", - "label": "ubuntu-latest" + "name": "TestLogPollerWithChaosPostgresFixedDepth" }, { - "name": "TestLogPollerReplayFixedDepth", - "label": "ubuntu-latest" + "name": "TestLogPollerReplayFixedDepth" }, { - "name": "TestLogPollerReplayFinalityTag", - "label": "ubuntu-latest" + "name": "TestLogPollerReplayFinalityTag" }, { - "name": "TestLogPollerManyFiltersFixedDepth", - "label": "ubuntu-latest" + "name": "TestLogPollerManyFiltersFixedDepth" }, { - "name": "TestLogPollerManyFiltersFinalityTag", - "label": "ubuntu-latest" + "name": "TestLogPollerManyFiltersFinalityTag" } ] } \ No newline at end of file diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 9834cd77973..77fe49f422d 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -3,6 +3,7 @@ package smoke import ( "fmt" "math/big" + "strconv" "strings" "sync" "testing" @@ -24,6 +25,7 @@ import ( 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/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -96,7 +98,7 @@ func TestVRFv2Basic(t *testing.T) { subIDForRequestRandomness := subIDsForRequestRandomness[0] subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subIDForRequestRandomness, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subIDForRequestRandomness, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) subBalanceBeforeRequest := subscription.Balance @@ -126,7 +128,7 @@ func TestVRFv2Basic(t *testing.T) { status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") require.Equal(t, *configCopy.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { @@ -152,7 +154,7 @@ func TestVRFv2Basic(t *testing.T) { subIDForJobRuns := subIDsForJobRuns[0] subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForJobRuns) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subIDForJobRuns, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subIDForJobRuns, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForJobRuns...) jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) @@ -276,7 +278,7 @@ func TestVRFv2Basic(t *testing.T) { subIDForOracleWithdraw := subIDsForOracleWithDraw[0] subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOracleWithdraw) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subIDForOracleWithdraw, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subIDForOracleWithdraw, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForOracleWithDraw...) fulfilledEventLink, err := vrfv2.RequestRandomnessAndWaitForFulfillment( @@ -337,7 +339,7 @@ func TestVRFv2Basic(t *testing.T) { subIDForCancelling := subIDsForCancelling[0] subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscription, subIDForCancelling, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscription, strconv.FormatUint(subIDForCancelling, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForCancelling...) testWalletAddress, err := actions.GenerateWallet() @@ -423,7 +425,7 @@ func TestVRFv2Basic(t *testing.T) { subIDForOwnerCancelling := subIDsForOwnerCancelling[0] subscriptionForCancelling, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOwnerCancelling) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForOwnerCancelling, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscriptionForCancelling, strconv.FormatUint(subIDForOwnerCancelling, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForOwnerCancelling...) // No GetActiveSubscriptionIds function available - skipping check @@ -590,7 +592,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { subIDForMultipleSendingKeys := subIDsForMultipleSendingKeys[0] subscriptionForMultipleSendingKeys, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForMultipleSendingKeys) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForMultipleSendingKeys, subIDForMultipleSendingKeys, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscriptionForMultipleSendingKeys, strconv.FormatUint(subIDForMultipleSendingKeys, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForMultipleSendingKeys...) txKeys, _, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") @@ -698,7 +700,7 @@ func TestVRFOwner(t *testing.T) { subIDForForceFulfill := subIDsForForceFulfill[0] subscriptionForMultipleSendingKeys, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForForceFulfill) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForMultipleSendingKeys, subIDForForceFulfill, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscriptionForMultipleSendingKeys, strconv.FormatUint(subIDForForceFulfill, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForForceFulfill...) vrfCoordinatorOwner, err := vrfContracts.CoordinatorV2.GetOwner(testcontext.Get(t)) @@ -748,7 +750,7 @@ func TestVRFOwner(t *testing.T) { status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") require.Equal(t, *configCopy.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { @@ -770,7 +772,7 @@ func TestVRFOwner(t *testing.T) { require.Equal(t, *configCopy.VRFv2.General.MinimumConfirmations, coordinatorConfig.MinimumRequestConfirmations) require.Equal(t, *configCopy.VRFv2.General.FulfillmentFlatFeeLinkPPMTier1, coordinatorFeeConfig.FulfillmentFlatFeeLinkPPMTier1) require.Equal(t, *configCopy.VRFv2.General.ReqsForTier2, coordinatorFeeConfig.ReqsForTier2.Int64()) - require.Equal(t, *configCopy.VRFv2.General.FallbackWeiPerUnitLink, coordinatorFallbackWeiPerUnitLinkConfig.Int64()) + require.Equal(t, *configCopy.VRFv2.General.FallbackWeiPerUnitLink, coordinatorFallbackWeiPerUnitLinkConfig.String()) }) } @@ -850,7 +852,7 @@ func TestVRFV2WithBHS(t *testing.T) { subIDForBHS := subIDsForBHS[0] subscriptionForBHS, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForBHS) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForBHS, subIDForBHS, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscriptionForBHS, strconv.FormatUint(subIDForBHS, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForBHS...) randomWordsRequestedEvent, err := vrfv2.RequestRandomness( @@ -867,7 +869,7 @@ func TestVRFV2WithBHS(t *testing.T) { ) require.NoError(t, err, "error requesting randomness") - vrfv2.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2, randomWordsRequestedEvent) + vrfcommon.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2, randomWordsRequestedEvent, false) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber var wg sync.WaitGroup wg.Add(1) @@ -878,15 +880,17 @@ func TestVRFV2WithBHS(t *testing.T) { err = vrfv2.FundSubscriptions(testEnv, chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDsForBHS) require.NoError(t, err, "error funding subscriptions") randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2.WaitForRandomWordsFulfilledEvent( - []*big.Int{randomWordsRequestedEvent.RequestId}, - time.Second*30, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{randomWordsRequestedEvent.RequestId}, + Timeout: configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfv2.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2, randomWordsFulfilledEvent) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2, randomWordsFulfilledEvent, false) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") }) t.Run("BHS Job should fill in blockhashes into BHS contract for unfulfilled requests", func(t *testing.T) { @@ -909,7 +913,7 @@ func TestVRFV2WithBHS(t *testing.T) { subIDForBHS := subIDsForBHS[0] subscriptionForBHS, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForBHS) require.NoError(t, err, "error getting subscription information") - vrfv2.LogSubDetails(l, subscriptionForBHS, subIDForBHS, vrfContracts.CoordinatorV2) + vrfcommon.LogSubDetails(l, subscriptionForBHS, strconv.FormatUint(subIDForBHS, 10), vrfContracts.CoordinatorV2) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForBHS...) randomWordsRequestedEvent, err := vrfv2.RequestRandomness( @@ -949,7 +953,7 @@ func TestVRFV2WithBHS(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { clNodeTxs, _, err = nodeTypeToNodeMap[vrfcommon.BHS].CLNode.API.ReadTransactions() g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") - l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") + l.Info().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) txHash = clNodeTxs.Data[0].Attributes.Hash }, "2m", "1s").Should(gomega.Succeed()) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index c5a35704b1a..36fc9d5268d 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -99,14 +100,11 @@ func TestVRFv2Plus(t *testing.T) { subIDForRequestRandomness := subIDsForRequestRandomness[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subIDForRequestRandomness, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subIDForRequestRandomness.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) subBalanceBeforeRequest := subscription.Balance - jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( consumers[0], @@ -129,14 +127,10 @@ func TestVRFv2Plus(t *testing.T) { subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") require.Equal(t, *configCopy.VRFv2Plus.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { @@ -163,14 +157,11 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) subNativeTokenBalanceBeforeRequest := subscription.NativeBalance - jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( consumers[0], @@ -191,14 +182,10 @@ func TestVRFv2Plus(t *testing.T) { subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") require.Equal(t, *testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { @@ -206,6 +193,45 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("CL Node VRF Job Runs", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + var isNativeBilling = false + consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForRequestRandomness := subIDsForRequestRandomness[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) + require.NoError(t, err, "error getting subscription information") + vrfcommon.LogSubDetails(l, subscription, subIDForRequestRandomness.String(), vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) + + jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + + // test and assert + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subIDForRequestRandomness, + isNativeBilling, + configCopy.VRFv2Plus.General, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + }) t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( @@ -262,7 +288,7 @@ func TestVRFv2Plus(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + vrfcommon.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) require.Equal(t, *testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { @@ -311,7 +337,7 @@ func TestVRFv2Plus(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + vrfcommon.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) require.Equal(t, *testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { @@ -336,7 +362,7 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) testWalletAddress, err := actions.GenerateWallet() @@ -444,7 +470,7 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) activeSubscriptionIdsBeforeSubCancellation, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err) @@ -593,7 +619,7 @@ func TestVRFv2Plus(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( @@ -730,7 +756,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) txKeys, _, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") @@ -839,7 +865,7 @@ func TestVRFv2PlusMigration(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) activeSubIdsOldCoordinatorBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) @@ -857,7 +883,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator) + _, 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)) err = newCoordinator.SetConfig( @@ -921,7 +947,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts) + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts.CoordinatorV2Plus) oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) @@ -939,7 +965,7 @@ func TestVRFv2PlusMigration(t *testing.T) { coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(testcontext.Get(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) - l.Debug(). + l.Info(). Str("Consumer", consumer.Address()). Str("Coordinator", coordinatorAddressInConsumerAfterMigration.String()). Msg("Coordinator Address in Consumer After Migration") @@ -976,7 +1002,7 @@ func TestVRFv2PlusMigration(t *testing.T) { require.Equal(t, 0, expectedEthTotalBalanceForOldCoordinator.Cmp(oldCoordinatorEthTotalBalanceAfterMigration)) //Verify rand requests fulfills with Link Token billing - _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( consumers[0], newCoordinator, vrfKey, @@ -988,7 +1014,7 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") //Verify rand requests fulfills with Native Token billing - _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( consumers[1], newCoordinator, vrfKey, @@ -1023,7 +1049,7 @@ func TestVRFv2PlusMigration(t *testing.T) { subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) activeSubIdsOldCoordinatorBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") @@ -1041,7 +1067,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator) + _, 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)) err = newCoordinator.SetConfig( @@ -1106,7 +1132,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts) + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts.CoordinatorV2Plus) oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) @@ -1123,7 +1149,7 @@ func TestVRFv2PlusMigration(t *testing.T) { coordinatorAddressInConsumerAfterMigration, err := wrapperContracts.VRFV2PlusWrapper.Coordinator(testcontext.Get(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract- VRFV2PlusWrapper") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) - l.Debug(). + l.Info(). Str("Consumer-VRFV2PlusWrapper", wrapperContracts.VRFV2PlusWrapper.Address()). Str("Coordinator", coordinatorAddressInConsumerAfterMigration.String()). Msg("Coordinator Address in VRFV2PlusWrapper After Migration") @@ -1160,7 +1186,7 @@ func TestVRFv2PlusMigration(t *testing.T) { // Verify rand requests fulfills with Link Token billing isNativeBilling := false - randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( + randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], newCoordinator, vrfKey, @@ -1176,7 +1202,7 @@ func TestVRFv2PlusMigration(t *testing.T) { // Verify rand requests fulfills with Native Token billing isNativeBilling = true - randomWordsFulfilledEvent, err = vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( + randomWordsFulfilledEvent, err = vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], newCoordinator, vrfKey, @@ -1269,28 +1295,20 @@ func TestVRFV2PlusWithBHS(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - _, err = consumers[0].RequestRandomness( - vrfKey.KeyHash, + randomWordsRequestedEvent, err := vrfv2plus.RequestRandomness( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, - *configCopy.VRFv2Plus.General.MinimumConfirmations, - *configCopy.VRFv2Plus.General.CallbackGasLimit, isNativeBilling, - *configCopy.VRFv2Plus.General.NumberOfWords, - *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + configCopy.VRFv2Plus.General, + l, ) require.NoError(t, err, "error requesting randomness") - randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKey.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumers[0].Address())}, - time.Minute*1, - ) - require.NoError(t, err, "error waiting for randomness requested event") - vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber var wg sync.WaitGroup wg.Add(1) @@ -1309,16 +1327,18 @@ func TestVRFV2PlusWithBHS(t *testing.T) { ) require.NoError(t, err, "error funding subscriptions") randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - time.Second*30, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{randomWordsRequestedEvent.RequestId}, + SubIDs: []*big.Int{subID}, + Timeout: configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, + }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfv2plus.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") randRequestBlockHash, err := vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) require.NoError(t, err, "error getting blockhash for a blocknumber which was stored in BHS contract") @@ -1350,29 +1370,20 @@ func TestVRFV2PlusWithBHS(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings - _, err = consumers[0].RequestRandomness( - vrfKey.KeyHash, + randomWordsRequestedEvent, err := vrfv2plus.RequestRandomness( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, - *configCopy.VRFv2Plus.General.MinimumConfirmations, - *configCopy.VRFv2Plus.General.CallbackGasLimit, isNativeBilling, - *configCopy.VRFv2Plus.General.NumberOfWords, - *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + configCopy.VRFv2Plus.General, + l, ) require.NoError(t, err, "error requesting randomness") - - randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKey.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumers[0].Address())}, - time.Minute*1, - ) - require.NoError(t, err, "error waiting for randomness requested event") - vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber _, 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") @@ -1385,6 +1396,9 @@ func TestVRFV2PlusWithBHS(t *testing.T) { 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))) var clNodeTxs *client.TransactionsData var txHash string @@ -1392,7 +1406,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { gom.Eventually(func(g gomega.Gomega) { clNodeTxs, _, err = nodeTypeToNodeMap[vrfcommon.BHS].CLNode.API.ReadTransactions() g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") - l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") + l.Info().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) txHash = clNodeTxs.Data[0].Attributes.Hash }, "2m", "1s").Should(gomega.Succeed()) @@ -1504,28 +1518,20 @@ func TestVRFV2PlusWithBHF(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - _, err = consumers[0].RequestRandomness( - vrfKey.KeyHash, + randomWordsRequestedEvent, err := vrfv2plus.RequestRandomness( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, - *configCopy.VRFv2Plus.General.MinimumConfirmations, - *configCopy.VRFv2Plus.General.CallbackGasLimit, isNativeBilling, - *configCopy.VRFv2Plus.General.NumberOfWords, - *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + configCopy.VRFv2Plus.General, + l, ) require.NoError(t, err, "error requesting randomness") - randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKey.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumers[0].Address())}, - time.Minute*1, - ) - require.NoError(t, err, "error waiting for randomness requested event") - vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber var wg sync.WaitGroup wg.Add(1) @@ -1547,16 +1553,18 @@ func TestVRFV2PlusWithBHF(t *testing.T) { ) require.NoError(t, err, "error funding subscriptions") randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - time.Minute*2, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{randomWordsRequestedEvent.RequestId}, + SubIDs: []*big.Int{subID}, + Timeout: configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, + }, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfv2plus.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + vrfcommon.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") clNodeTxs, _, err := nodeTypeToNodeMap[vrfcommon.BHF].CLNode.API.ReadTransactions() require.NoError(t, err, "error fetching txns from BHF node") @@ -1653,11 +1661,11 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) // 2. create request but without fulfilment - e.g. simulation failure (insufficient balance in the sub, ) - initialReqRandomWordsRequestedEvent, err := vrfv2plus.RequestRandomnessAndWaitForRequestedEvent( + initialReqRandomWordsRequestedEvent, err := vrfv2plus.RequestRandomness( consumers[0], vrfContracts.CoordinatorV2Plus, vrfKey, @@ -1758,9 +1766,11 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { Str("subID", subID.String()). Msg("Waiting for initalReqRandomWordsFulfilledEvent") initalReqRandomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{initialReqRandomWordsRequestedEvent.RequestId}, - configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, + contracts.RandomWordsFulfilledEventFilter{ + RequestIds: []*big.Int{initialReqRandomWordsRequestedEvent.RequestId}, + SubIDs: []*big.Int{subID}, + Timeout: configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, + }, ) require.NoError(t, err, "error waiting for initial request RandomWordsFulfilledEvent") @@ -1844,7 +1854,7 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + vrfcommon.LogSubDetails(l, subscription, subID.String(), vrfContracts.CoordinatorV2Plus) subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) var isNativeBilling = true diff --git a/integration-tests/testconfig/common/vrf/common.go b/integration-tests/testconfig/common/vrf/common.go index 0f0893f687c..a5b4078f429 100644 --- a/integration-tests/testconfig/common/vrf/common.go +++ b/integration-tests/testconfig/common/vrf/common.go @@ -142,7 +142,7 @@ type General struct { NumberOfWords *uint32 `toml:"number_of_words"` // Number of words to request CallbackGasLimit *uint32 `toml:"callback_gas_limit"` // Gas limit for the callback MaxGasLimitCoordinatorConfig *uint32 `toml:"max_gas_limit_coordinator_config"` // Max gas limit for the VRF Coordinator config - FallbackWeiPerUnitLink *int64 `toml:"fallback_wei_per_unit_link"` // Fallback wei per unit LINK for the VRF Coordinator config + FallbackWeiPerUnitLink *string `toml:"fallback_wei_per_unit_link"` // Fallback wei per unit LINK for the VRF Coordinator config StalenessSeconds *uint32 `toml:"staleness_seconds"` // Staleness in seconds for the VRF Coordinator config GasAfterPaymentCalculation *uint32 `toml:"gas_after_payment_calculation"` // Gas after payment calculation for the VRF Coordinator @@ -156,11 +156,9 @@ type General struct { WaitFor256BlocksTimeout *blockchain.StrDuration `toml:"wait_for_256_blocks_timeout"` // How long to wait for 256 blocks to be mined // Wrapper Config - WrapperGasOverhead *uint32 `toml:"wrapped_gas_overhead"` - CoordinatorGasOverhead *uint32 `toml:"coordinator_gas_overhead"` - CoordinatorGasOverheadPerWord *uint16 `toml:"coordinator_gas_overhead_per_word"` - WrapperPremiumPercentage *uint8 `toml:"wrapper_premium_percentage"` - WrapperMaxNumberOfWords *uint8 `toml:"wrapper_max_number_of_words"` + WrapperGasOverhead *uint32 `toml:"wrapped_gas_overhead"` + WrapperMaxNumberOfWords *uint8 `toml:"wrapper_max_number_of_words"` + WrapperConsumerFundingAmountNativeToken *float64 `toml:"wrapper_consumer_funding_amount_native_token"` WrapperConsumerFundingAmountLink *int64 `toml:"wrapper_consumer_funding_amount_link"` @@ -214,8 +212,8 @@ func (c *General) Validate() error { if c.MaxGasLimitCoordinatorConfig == nil || *c.MaxGasLimitCoordinatorConfig == 0 { return errors.New("max_gas_limit_coordinator_config must be set to a positive value") } - if c.FallbackWeiPerUnitLink == nil || *c.FallbackWeiPerUnitLink == 0 { - return errors.New("fallback_wei_per_unit_link must be set to a positive value") + if c.FallbackWeiPerUnitLink == nil { + return errors.New("fallback_wei_per_unit_link must be set") } if c.StalenessSeconds == nil || *c.StalenessSeconds == 0 { return errors.New("staleness_seconds must be set to a positive value") @@ -246,12 +244,6 @@ func (c *General) Validate() error { if c.WrapperGasOverhead == nil { return errors.New("wrapped_gas_overhead must be set to a non-negative value") } - if c.CoordinatorGasOverhead == nil || *c.CoordinatorGasOverhead == 0 { - return errors.New("coordinator_gas_overhead must be set to a non-negative value") - } - if c.WrapperPremiumPercentage == nil || *c.WrapperPremiumPercentage == 0 { - return errors.New("wrapper_premium_percentage must be set to a positive value") - } if c.WrapperMaxNumberOfWords == nil || *c.WrapperMaxNumberOfWords == 0 { return errors.New("wrapper_max_number_of_words must be set to a positive value") } diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index a277c22b4c2..ef3f60d4282 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -43,6 +43,10 @@ ephemeral_addresses_number = 0 # That's because the one we are about to send would get queued, possibly for a very long time pending_nonce_protection_enabled = false +# when enabled when creating a new Seth client we will send 10k wei from root address to root address +# to make sure transaction can be submited and mined +check_rpc_health_on_start = false + [Seth.nonce_manager] key_sync_rate_limit_per_sec = 10 key_sync_timeout = "2s" diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go index dcfd959880b..76d54a45d5b 100644 --- a/integration-tests/testconfig/vrfv2/config.go +++ b/integration-tests/testconfig/vrfv2/config.go @@ -72,6 +72,8 @@ type General struct { ReqsForTier3 *int64 `toml:"reqs_for_tier_3"` ReqsForTier4 *int64 `toml:"reqs_for_tier_4"` ReqsForTier5 *int64 `toml:"reqs_for_tier_5"` + CoordinatorGasOverhead *uint32 `toml:"coordinator_gas_overhead"` + WrapperPremiumPercentage *uint8 `toml:"wrapper_premium_percentage"` } func (c *General) Validate() error { @@ -107,6 +109,11 @@ func (c *General) Validate() error { if c.ReqsForTier5 == nil || *c.ReqsForTier5 < 0 { return errors.New("reqs_for_tier_5 must be set to a non-negative value") } - + if c.CoordinatorGasOverhead == nil || *c.CoordinatorGasOverhead == 0 { + return errors.New("coordinator_gas_overhead must be set to a non-negative value") + } + if c.WrapperPremiumPercentage == nil || *c.WrapperPremiumPercentage == 0 { + return errors.New("wrapper_premium_percentage must be set to a positive value") + } return nil } diff --git a/integration-tests/testconfig/vrfv2/example.toml b/integration-tests/testconfig/vrfv2/example.toml index 53d0888f6d4..8a8139b92d4 100644 --- a/integration-tests/testconfig/vrfv2/example.toml +++ b/integration-tests/testconfig/vrfv2/example.toml @@ -84,7 +84,7 @@ subscription_funding_amount_link = 5.0 number_of_words = 3 callback_gas_limit = 1000000 max_gas_limit_coordinator_config = 2500000 -fallback_wei_per_unit_link = 60000000000000000 +fallback_wei_per_unit_link = "60000000000000000" staleness_seconds = 86400 gas_after_payment_calculation = 33825 fulfilment_flat_fee_link_ppm_tier_1 = 500 diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml index 6d92e2fd6b0..012352f49b8 100644 --- a/integration-tests/testconfig/vrfv2/vrfv2.toml +++ b/integration-tests/testconfig/vrfv2/vrfv2.toml @@ -16,7 +16,7 @@ minimum_confirmations = 3 number_of_words = 3 callback_gas_limit = 1000000 max_gas_limit_coordinator_config = 2500000 -fallback_wei_per_unit_link = 60000000000000000 +fallback_wei_per_unit_link = "60000000000000000" staleness_seconds = 86400 gas_after_payment_calculation = 33825 fulfilment_flat_fee_link_ppm_tier_1 = 500 diff --git a/integration-tests/testconfig/vrfv2plus/config.go b/integration-tests/testconfig/vrfv2plus/config.go index b87bef6a836..eb5ba061984 100644 --- a/integration-tests/testconfig/vrfv2plus/config.go +++ b/integration-tests/testconfig/vrfv2plus/config.go @@ -45,10 +45,16 @@ type General struct { SubscriptionFundingAmountNative *float64 `toml:"subscription_funding_amount_native"` // Amount of LINK to fund the subscription with SubscriptionRefundingAmountNative *float64 `toml:"subscription_refunding_amount_native"` // Amount of LINK to fund the subscription with FulfillmentFlatFeeNativePPM *uint32 `toml:"fulfillment_flat_fee_native_ppm"` // Flat fee in ppm for native currency for the VRF Coordinator config - FulfillmentFlatFeeLinkPPM *uint32 `toml:"fulfillment_flat_fee_link_ppm"` // Flat fee in ppm for LINK for the VRF Coordinator config FulfillmentFlatFeeLinkDiscountPPM *uint32 `toml:"fulfillment_flat_fee_link_discount_ppm"` // Flat fee discount in ppm for LINK for the VRF Coordinator config NativePremiumPercentage *uint8 `toml:"native_premium_percentage"` // Native Premium Percentage LinkPremiumPercentage *uint8 `toml:"link_premium_percentage"` // LINK Premium Percentage + + //Wrapper config + CoordinatorGasOverheadPerWord *uint16 `toml:"coordinator_gas_overhead_per_word"` + CoordinatorGasOverheadNative *uint32 `toml:"coordinator_gas_overhead_native"` + CoordinatorGasOverheadLink *uint32 `toml:"coordinator_gas_overhead_link"` + CoordinatorNativePremiumPercentage *uint8 `toml:"coordinator_native_premium_percentage"` + CoordinatorLinkPremiumPercentage *uint8 `toml:"coordinator_link_premium_percentage"` } func (c *General) Validate() error { @@ -67,9 +73,6 @@ func (c *General) Validate() error { if c.FulfillmentFlatFeeNativePPM == nil { return errors.New("fulfillment_flat_fee_native_ppm must not be nil") } - if c.FulfillmentFlatFeeLinkPPM == nil { - return errors.New("fulfillment_flat_fee_link_ppm must not be nil") - } if c.FulfillmentFlatFeeLinkDiscountPPM == nil { return errors.New("fulfillment_flat_fee_link_discount_ppm must not be nil") } @@ -79,6 +82,21 @@ func (c *General) Validate() error { if c.LinkPremiumPercentage == nil { return errors.New("link_premium_percentage must not be nil") } + if c.CoordinatorGasOverheadPerWord == nil { + return errors.New("coordinator_gas_overhead_per_word must not be nil") + } + if c.CoordinatorGasOverheadNative == nil || *c.CoordinatorGasOverheadNative == 0 { + return errors.New("coordinator_gas_overhead_native must be set to a non-negative value") + } + if c.CoordinatorGasOverheadLink == nil || *c.CoordinatorGasOverheadLink == 0 { + return errors.New("coordinator_gas_overhead_link must be set to a non-negative value") + } + if c.CoordinatorNativePremiumPercentage == nil { + return errors.New("coordinator_native_premium_percentage must not be nil") + } + if c.CoordinatorLinkPremiumPercentage == nil { + return errors.New("coordinator_link_premium_percentage must not be nil") + } return nil } diff --git a/integration-tests/testconfig/vrfv2plus/example.toml b/integration-tests/testconfig/vrfv2plus/example.toml index a0db80bdc2f..76fe23a2e70 100644 --- a/integration-tests/testconfig/vrfv2plus/example.toml +++ b/integration-tests/testconfig/vrfv2plus/example.toml @@ -85,7 +85,7 @@ subscription_funding_amount_link = 5.0 number_of_words = 3 callback_gas_limit = 1000000 max_gas_limit_coordinator_config = 2500000 -fallback_wei_per_unit_link = 60000000000000000 +fallback_wei_per_unit_link = "60000000000000000" staleness_seconds = 86400 gas_after_payment_calculation = 33825 fulfilment_flat_fee_link_ppm_tier_1 = 500 @@ -102,14 +102,14 @@ randomness_request_count_per_request = 1 randomness_request_count_per_request_deviation = 0 random_words_fulfilled_event_timeout = "2m" wrapped_gas_overhead = 50000 -coordinator_gas_overhead = 52000 +coordinator_gas_overhead_native = 52000 +coordinator_gas_overhead_link = 74000 coordinator_gas_overhead_per_word = 440 wrapper_premium_percentage = 25 wrapper_max_number_of_words = 10 wrapper_consumer_funding_amount_native_token = 1.0 wrapper_consumer_funding_amount_link = 10 subscription_funding_amount_native=1 -fulfillment_flat_fee_link_ppm=500 fulfillment_flat_fee_native_ppm=500 fulfillment_flat_fee_link_discount_ppm=100 native_premium_percentage=1 diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index 111d3c4cf71..902ca3a2966 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -20,7 +20,7 @@ subscription_billing_type = "LINK_AND_NATIVE" number_of_words = 3 callback_gas_limit = 1000000 max_gas_limit_coordinator_config = 2500000 -fallback_wei_per_unit_link = 60000000000000000 +fallback_wei_per_unit_link = "60000000000000000" staleness_seconds = 86400 gas_after_payment_calculation = 33825 number_of_sub_to_create = 1 @@ -29,18 +29,21 @@ randomness_request_count_per_request = 1 randomness_request_count_per_request_deviation = 0 random_words_fulfilled_event_timeout = "2m" wait_for_256_blocks_timeout = "10m" + +fulfillment_flat_fee_native_ppm=0 +fulfillment_flat_fee_link_discount_ppm=0 +native_premium_percentage=24 +link_premium_percentage=20 + wrapped_gas_overhead = 50000 -coordinator_gas_overhead = 52000 +coordinator_gas_overhead_native = 52000 +coordinator_gas_overhead_link = 74000 coordinator_gas_overhead_per_word = 440 -wrapper_premium_percentage = 25 wrapper_max_number_of_words = 10 wrapper_consumer_funding_amount_native_token = 1.0 wrapper_consumer_funding_amount_link = 10 -fulfillment_flat_fee_link_ppm=500 -fulfillment_flat_fee_native_ppm=500 -fulfillment_flat_fee_link_discount_ppm=100 -native_premium_percentage=1 -link_premium_percentage=1 +coordinator_native_premium_percentage=24 +coordinator_link_premium_percentage=20 # VRF Job config vrf_job_forwarding_allowed = false diff --git a/main_test.go b/main_test.go index 51707f0d9fb..81e056e3b84 100644 --- a/main_test.go +++ b/main_test.go @@ -43,6 +43,9 @@ func TestMain(m *testing.M) { } func TestScripts(t *testing.T) { + if testing.Short() { + t.Skip("skipping testscript") + } t.Parallel() visitor := txtar.NewDirVisitor("testdata/scripts", txtar.Recurse, func(path string) error { diff --git a/operator_ui/check.sh b/operator_ui/check.sh index 9e738218088..e4e12209b05 100755 --- a/operator_ui/check.sh +++ b/operator_ui/check.sh @@ -6,7 +6,7 @@ set -e # jq ^1.6 https://stedolan.github.io/jq/ repo=smartcontractkit/operator-ui -gitRoot=$(git rev-parse --show-toplevel) +gitRoot="$(dirname -- "$0")/../" cd "$gitRoot/operator_ui" tag_file=TAG diff --git a/operator_ui/install.sh b/operator_ui/install.sh index 0de72d51f4e..f86c9a2f352 100755 --- a/operator_ui/install.sh +++ b/operator_ui/install.sh @@ -4,7 +4,7 @@ set -e owner=smartcontractkit repo=operator-ui fullRepo=${owner}/${repo} -gitRoot=$(git rev-parse --show-toplevel || pwd) +gitRoot="$(dirname -- "$0")/../" cd "$gitRoot/operator_ui" unpack_dir="$gitRoot/core/web/assets" tag=$(cat TAG) diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index 9c7f71183f0..50986396296 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -62,7 +62,7 @@ RUN apt-get update && apt-get install -y ca-certificates gnupg lsb-release curl # Install Postgres for CLI tools, needed specifically for DB backups RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |tee /etc/apt/sources.list.d/pgdg.list \ - && apt-get update && apt-get install -y postgresql-client-14 \ + && apt-get update && apt-get install -y postgresql-client-16 \ && apt-get clean all COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ diff --git a/plugins/medianpoc/data_source.go b/plugins/medianpoc/data_source.go index 060dddc2938..3bb6e51593e 100644 --- a/plugins/medianpoc/data_source.go +++ b/plugins/medianpoc/data_source.go @@ -11,13 +11,13 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type DataSource struct { - pipelineRunner types.PipelineRunnerService + pipelineRunner core.PipelineRunnerService spec string lggr logger.Logger @@ -32,13 +32,13 @@ func (d *DataSource) Observe(ctx context.Context, reportTimestamp ocrtypes.Repor } // NOTE: job metadata is automatically attached by the pipeline runner service - vars := types.Vars{ + vars := core.Vars{ Vars: map[string]interface{}{ "jobRun": md, }, } - results, err := d.pipelineRunner.ExecuteRun(ctx, d.spec, vars, types.Options{}) + results, err := d.pipelineRunner.ExecuteRun(ctx, d.spec, vars, core.Options{}) if err != nil { return nil, err } @@ -77,3 +77,9 @@ func (d *DataSource) updateAnswer(latestAnswer *big.Int) { UpdatedAt: big.NewInt(time.Now().Unix()), } } + +type ZeroDataSource struct{} + +func (d *ZeroDataSource) Observe(ctx context.Context, reportTimestamp ocrtypes.ReportTimestamp) (*big.Int, error) { + return new(big.Int), nil +} diff --git a/plugins/medianpoc/data_source_test.go b/plugins/medianpoc/data_source_test.go index e9d95b01b02..6680ad0e79c 100644 --- a/plugins/medianpoc/data_source_test.go +++ b/plugins/medianpoc/data_source_test.go @@ -15,18 +15,18 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" ) type mockPipelineRunner struct { - results types.TaskResults + results core.TaskResults err error spec string - vars types.Vars - options types.Options + vars core.Vars + options core.Options } -func (m *mockPipelineRunner) ExecuteRun(ctx context.Context, spec string, vars types.Vars, options types.Options) (types.TaskResults, error) { +func (m *mockPipelineRunner) ExecuteRun(ctx context.Context, spec string, vars core.Vars, options core.Options) (core.TaskResults, error) { m.spec = spec m.vars = vars m.options = options @@ -37,9 +37,9 @@ func TestDataSource(t *testing.T) { lggr := logger.TestLogger(t) expect := jsonserializable.JSONSerializable{Val: int64(3), Valid: true} pr := &mockPipelineRunner{ - results: types.TaskResults{ + results: core.TaskResults{ { - TaskValue: types.TaskValue{ + TaskValue: core.TaskValue{ Value: expect, Error: nil, IsTerminal: true, @@ -47,7 +47,7 @@ func TestDataSource(t *testing.T) { Index: 2, }, { - TaskValue: types.TaskValue{ + TaskValue: core.TaskValue{ Value: jsonserializable.JSONSerializable{Val: int64(4), Valid: true}, Error: nil, IsTerminal: false, @@ -73,9 +73,9 @@ func TestDataSource(t *testing.T) { func TestDataSource_ResultErrors(t *testing.T) { lggr := logger.TestLogger(t) pr := &mockPipelineRunner{ - results: types.TaskResults{ + results: core.TaskResults{ { - TaskValue: types.TaskValue{ + TaskValue: core.TaskValue{ Error: errors.New("something went wrong"), IsTerminal: true, }, @@ -98,9 +98,9 @@ func TestDataSource_ResultNotAnInt(t *testing.T) { expect := jsonserializable.JSONSerializable{Val: "string-result", Valid: true} pr := &mockPipelineRunner{ - results: types.TaskResults{ + results: core.TaskResults{ { - TaskValue: types.TaskValue{ + TaskValue: core.TaskValue{ Value: expect, IsTerminal: true, }, diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go index 76fb4651260..b937361b9ec 100644 --- a/plugins/medianpoc/plugin.go +++ b/plugins/medianpoc/plugin.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" ) func NewPlugin(lggr logger.Logger) *Plugin { @@ -29,7 +30,7 @@ type Plugin struct { reportingplugins.MedianProviderServer } -func (p *Plugin) NewValidationService(ctx context.Context) (types.ValidationService, error) { +func (p *Plugin) NewValidationService(ctx context.Context) (core.ValidationService, error) { s := &reportingPluginValidationService{lggr: p.Logger} p.SubService(s) return s, nil @@ -59,12 +60,12 @@ func (j jsonConfig) getPipeline(key string) (string, error) { func (p *Plugin) NewReportingPluginFactory( ctx context.Context, - config types.ReportingPluginServiceConfig, + config core.ReportingPluginServiceConfig, provider types.MedianProvider, - pipelineRunner types.PipelineRunnerService, - telemetry types.TelemetryClient, - errorLog types.ErrorLog, - keyValueStore types.KeyValueStore, + pipelineRunner core.PipelineRunnerService, + telemetry core.TelemetryClient, + errorLog core.ErrorLog, + keyValueStore core.KeyValueStore, ) (types.ReportingPluginFactory, error) { f, err := p.newFactory(ctx, config, provider, pipelineRunner, telemetry, errorLog) if err != nil { @@ -75,7 +76,7 @@ func (p *Plugin) NewReportingPluginFactory( return s, nil } -func (p *Plugin) newFactory(ctx context.Context, config types.ReportingPluginServiceConfig, provider types.MedianProvider, pipelineRunner types.PipelineRunnerService, telemetry types.TelemetryClient, errorLog types.ErrorLog) (*median.NumericalMedianFactory, error) { +func (p *Plugin) newFactory(ctx context.Context, config core.ReportingPluginServiceConfig, provider types.MedianProvider, pipelineRunner core.PipelineRunnerService, telemetry core.TelemetryClient, errorLog core.ErrorLog) (*median.NumericalMedianFactory, error) { jc := &jsonConfig{} err := json.Unmarshal([]byte(config.PluginConfig), jc) if err != nil { @@ -102,9 +103,11 @@ func (p *Plugin) newFactory(ctx context.Context, config types.ReportingPluginSer lggr: p.Logger, } factory := &median.NumericalMedianFactory{ - ContractTransmitter: provider.MedianContract(), - DataSource: ds, - JuelsPerFeeCoinDataSource: jds, + ContractTransmitter: provider.MedianContract(), + DataSource: ds, + JuelsPerFeeCoinDataSource: jds, + GasPriceSubunitsDataSource: &ZeroDataSource{}, + IncludeGasPriceSubunitsInObservation: false, Logger: logger.NewOCRWrapper( p.Logger, true, diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index d4470eef70a..673c1fabc7d 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -11,13 +11,14 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" ) type mockErrorLog struct { - types.ErrorLog + core.ErrorLog } type mockOffchainConfigDigester struct { @@ -86,7 +87,7 @@ func TestNewPlugin(t *testing.T) { defaultSpec := "default-spec" juelsPerFeeCoinSpec := "jpfc-spec" - config := types.ReportingPluginServiceConfig{ + config := core.ReportingPluginServiceConfig{ PluginConfig: fmt.Sprintf( `{"pipelines": [{"name": "__DEFAULT_PIPELINE__", "spec": "%s"},{"name": "juelsPerFeeCoinPipeline", "spec": "%s"}]}`, defaultSpec, diff --git a/shell.nix b/shell.nix index ca785283fd5..69bf202351d 100644 --- a/shell.nix +++ b/shell.nix @@ -42,6 +42,9 @@ mkShell' { kubectl kubernetes-helm + # cross-compiling, used in CRIB + zig + # gofuzz ] ++ lib.optionals stdenv.isLinux [ # some dependencies needed for node-gyp on pnpm install diff --git a/testdata/scripts/health/multi-chain.txtar b/testdata/scripts/health/multi-chain.txtar index 112d9e3cdb1..fd48c0ad1ce 100644 --- a/testdata/scripts/health/multi-chain.txtar +++ b/testdata/scripts/health/multi-chain.txtar @@ -61,6 +61,7 @@ URL = 'http://stark.node' -- out.txt -- ok Cosmos.Foo.Chain +ok Cosmos.Foo.Relayer ok Cosmos.Foo.Txm ok EVM.1 ok EVM.1.BalanceMonitor @@ -97,6 +98,15 @@ ok TelemetryManager "output": "" } }, + { + "type": "checks", + "id": "Cosmos.Foo.Relayer", + "attributes": { + "name": "Cosmos.Foo.Relayer", + "status": "passing", + "output": "" + } + }, { "type": "checks", "id": "Cosmos.Foo.Txm",